POJ 2528 Mayor's posters 线段树+离散化
2015-02-09 15:57
246 查看
题目链接 http://poj.org/problem?id=2528
题意: 有长度为 10000000 的一堵墙, n个市长按照先后顺序在 L 到 R 区间之间张贴海报,问最后能看见几个人的海报, 后面的海报会覆盖掉前面的海报.
自身无法作为数组的下标保存对应的属性。
如果这时只是需要这堆数据的相对属性,
那么可以对其进行离散化处理!
离散化:当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。
例如
9
1 0 5 4 与 5 2 1 4 3 的逆序对个数相同。
设有4个数:
1234567、123456789、12345678、123456
排序:123456<1234567<12345678<123456789
=> 1 < 2 < 3 < 4
那么这4个数可以表示成:2、4、3、1
假定待离散化的序列为a
,b
是序列a
的一个副本,则对应以上三步为:
+
1;//k为b[i]经离散化后对应的值
对于第3步,若离散化后序列为0, 1, 2, ..., size - 1则用lower_bound,从1, 2, 3, ..., size则用upper_bound,其中lower_bound返回第1个不小于b[i]的值的指针,而upper_bound返回第1个大于b[i]的值的指针,当然在这个题中也可以用lower_bound然后再加1得到与upper_bound相同结果,两者都是针对以排好序列。使用STL离散化大大减少了代码量且结构相当清晰。
线段树的区间更新和查询;
先把这 2 * n 个节点 按照 从小到大顺序 排序, 建立映射, 在 更新树 更新的节点 是映射之后的小区间的节点.
方案一: 对 falg 数组排序,下面在通过 二分查找, 找到 这个结点在 已排好序的flag数组的下标, 这个下标就是他的映射;
方案二: 用 hash 数组 存下标,不用查找了,但是这个方法即浪费内存,也耗时,没有二分快.------------当然还有其他很多方法,比如map等等
题意: 有长度为 10000000 的一堵墙, n个市长按照先后顺序在 L 到 R 区间之间张贴海报,问最后能看见几个人的海报, 后面的海报会覆盖掉前面的海报.
先了解一下离散化吧(传送门):
有些数据本身很大,自身无法作为数组的下标保存对应的属性。
如果这时只是需要这堆数据的相对属性,
那么可以对其进行离散化处理!
离散化:当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。
例如
9
1 0 5 4 与 5 2 1 4 3 的逆序对个数相同。
设有4个数:
1234567、123456789、12345678、123456
排序:123456<1234567<12345678<123456789
=> 1 < 2 < 3 < 4
那么这4个数可以表示成:2、4、3、1
使用STL算法离散化:
思路:先排序,再删除重复元素,然后就是索引元素离散化后对应的值。假定待离散化的序列为a
,b
是序列a
的一个副本,则对应以上三步为:
<pre name="code" class="sh_cpp sh_sourceCode" style="background-color:white; font-size:16px; font-family:'Courier New',Courier,monospace"><span class="sh_function" style="font-weight:bold">sort</span><span class="sh_symbol" style="color:#8b00;">(</span>sub_a<span class="sh_symbol" style="color:#8b00;">,</span>sub_a<span class="sh_symbol" style="color:#8b00;">+</span>n<span class="sh_symbol" style="color:#8b00;">);</span>
<span class="sh_type" style="color:#0640;">int</span> size<span class="sh_symbol" style="color:#8b00;">=</span><span class="sh_function" style="font-weight:bold">unique</span><span class="sh_symbol" style="color:#8b00;">(</span>sub_a<span class="sh_symbol" style="color:#8b00;">,</span>sub_a<span class="sh_symbol" style="color:#8b00;">+</span>n<span class="sh_symbol" style="color:#8b00;">)-</span>sub_a<span class="sh_symbol" style="color:#8b00;">;</span><span style="font-family:Georgia,'Bitstream Charter',serif;font-size:16px">//size为离散化后元素个数</span>
<span class="sh_keyword" style="color:blue;font-weight:bold">for</span><span class="sh_symbol" style="color:#8b00;">(</span>i<span class="sh_symbol" style="color:#8b00;">=</span><span class="sh_number" style="color:purple;">0</span><span class="sh_symbol" style="color:#8b00;">;</span>i<span class="sh_symbol" style="color:#8b00;"><</span>n<span class="sh_symbol" style="color:#8b00;">;</span>i<span class="sh_symbol" style="color:#8b00;">++)</span>a[i]=lower_bound(sub_a,sub_a+size,a[i])-sub_a
+
1;//k为b[i]经离散化后对应的值
对于第3步,若离散化后序列为0, 1, 2, ..., size - 1则用lower_bound,从1, 2, 3, ..., size则用upper_bound,其中lower_bound返回第1个不小于b[i]的值的指针,而upper_bound返回第1个大于b[i]的值的指针,当然在这个题中也可以用lower_bound然后再加1得到与upper_bound相同结果,两者都是针对以排好序列。使用STL离散化大大减少了代码量且结构相当清晰。
解题思路:
观察 墙的长度 是 10000000, 询问是有 10000 个, 每次询问有两个节点,也就是有10000 * 2个节点,如果按长度建立线段树, 会MLE(试过了~~~~(>_<)~~~~ ),所以应该按照节点数建立线段树, 但是要把节点离散化,建立一个映射关系. 因为节点的大小是在 10000000 以内的.线段树的区间更新和查询;
先把这 2 * n 个节点 按照 从小到大顺序 排序, 建立映射, 在 更新树 更新的节点 是映射之后的小区间的节点.
方案一: 对 falg 数组排序,下面在通过 二分查找, 找到 这个结点在 已排好序的flag数组的下标, 这个下标就是他的映射;
方案二: 用 hash 数组 存下标,不用查找了,但是这个方法即浪费内存,也耗时,没有二分快.------------当然还有其他很多方法,比如map等等
代码1 1176K 235MS
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define maxm 20005 struct Tree { int left, right, num; }node[maxm << 2]; struct A { int l, r; }a[maxm]; int hash[maxm], ans = 0, flag[maxm]; void BuildTree(int i, int l, int r); void Update(int i, int num, int l, int r); void PushDown(int i); void Query(int i); int Find(int num , int l , int r); int main() { int t, n, i, j, x, y; scanf("%d", &t); while(t--) { scanf("%d", &n); for(i = 1; i <= n; i++) { scanf("%d %d", &a[i].l, &a[i].r); flag[2*i-1] = a[i].l , flag[2*i] = a[i].r; } sort(flag + 1 , flag + 2*n + 1); BuildTree(1, 1, maxm); for(i = 1; i <= n; i++) { x = Find(a[i].l , 1 , 2*n); y = Find(a[i].r , 1 , 2*n); Update(1, i, x, y); } memset(hash, 0, sizeof(hash)); ans = 0; Query(1); printf("%d\n", ans); } } void BuildTree(int i, int l, int r) { node[i].left = l; node[i].right = r; node[i].num = 0; if(l == r) return; int mid = (l + r) >> 1; BuildTree(i << 1, l, mid); BuildTree(i << 1 | 1, mid + 1, r); } void Update(int i, int num, int l, int r) { if(node[i].left == l && node[i].right == r) { node[i].num = num; return; } if(node[i].num != -1) { PushDown(i); node[i].num = -1; } int mid = (node[i].left + node[i].right) >> 1; if(r <= mid) Update(i << 1, num, l, r); else if(l > mid) Update(i << 1 | 1, num, l, r); else { Update(i << 1, num, l, mid); Update(i << 1 | 1, num, mid + 1, r); } } void PushDown(int i) { node[i << 1].num = node[i << 1 | 1].num = node[i].num; } void Query(int i) { if(node[i].num != -1) { if(node[i].num > 0 && hash[node[i].num] == 0) { hash[node[i].num] = 1; ans++; } return; } else { Query(i << 1); Query(i << 1 | 1); } } int Find(int num , int l , int r) { if(l > r) return 0; int mid = (l + r) >> 1; if(flag[mid] == num) { int i = mid - 1; for( ; i > 0 ; --i) { if(flag[i] != num) break; } return i + 1; } if(flag[mid] < num) return Find(num , mid + 1 , r); else return Find(num , l , mid - 1); }
代码2: 40272K 625MS
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define maxn 10000005 #define maxm 20005 struct Tree { int left, right, num; }node[maxm << 2]; struct A { int l, r; }a[maxm]; int hash[maxn], ans = 0, flag[maxm]; void BuildTree(int i, int l, int r); void Update(int i, int num, int l, int r); void PushDown(int i); void Query(int i); int main() { int t, n, i, j, x, y; scanf("%d", &t); while(t--) { scanf("%d", &n); for(i = 1; i <= n; i++) { scanf("%d %d", &a[i].l, &a[i].r); flag[2*i-1] = a[i].l , flag[2*i] = a[i].r; } sort(flag + 1 , flag + 2*n + 1); j = 1; memset(hash, 0, sizeof(hash)); for(i = 1; i <= 2 * n; i++) { if(!hash[flag[i]]) hash[flag[i]] = j++; } BuildTree(1, 1, maxm); for(i = 1; i <= n; i++) { x = hash[a[i].l]; y = hash[a[i].r]; Update(1, i, x, y); } memset(hash, 0, sizeof(hash)); ans = 0; Query(1); printf("%d\n", ans); } } void BuildTree(int i, int l, int r) { node[i].left = l; node[i].right = r; node[i].num = 0; if(l == r) return; int mid = (l + r) >> 1; BuildTree(i << 1, l, mid); BuildTree(i << 1 | 1, mid + 1, r); } void Update(int i, int num, int l, int r) { if(node[i].left == l && node[i].right == r) { node[i].num = num; return; } if(node[i].num != -1) { PushDown(i); node[i].num = -1; } int mid = (node[i].left + node[i].right) >> 1; if(r <= mid) Update(i << 1, num, l, r); else if(l > mid) Update(i << 1 | 1, num, l, r); else { Update(i << 1, num, l, mid); Update(i << 1 | 1, num, mid + 1, r); } } void PushDown(int i) { node[i << 1].num = node[i << 1 | 1].num = node[i].num; } void Query(int i) { if(node[i].num != -1) { if(node[i].num > 0 && hash[node[i].num] == 0) { hash[node[i].num] = 1; ans++; } return; } else { Query(i << 1); Query(i << 1 | 1); } }
相关文章推荐
- POJ 2528 Mayor's posters 线段树+离散化
- poj - 2528 - Mayor's posters 线段树+离散化
- poj 2528 Mayor's posters 线段树+离散化
- POJ 2528 Mayor's posters 线段树+离散化
- POJ 2528 Mayor&#39;s posters --线段树+离散化
- POJ 2528 Mayor's posters 线段树
- POJ 2528 Mayor's posters【线段树+离散化】
- POJ 2528 Mayor's posters 线段树的区间覆盖 离散化
- POJ 2528 Mayor's posters 线段树+离散化
- POJ-2528 Mayor's posters 线段树+离散
- Mayor's posters poj 2528
- POJ 2528 Mayor's posters 线段树和离散化
- poj 2528 Mayor's posters 线段树+离散话!!!
- pku 2528 Mayor's posters-线段树+离散化
- POJ 2528 Mayor's posters 离散化+线段树
- POJ 2528 Mayor's posters 离散化和线段树题解
- poj 2528 Mayor's posters【离散化+线段树】
- POJ 2528 Mayor's posters 线段树
- (重温)poj 2528 Mayor's posters 线段树 染色+离散化
- POJ 2528 Mayor's posters 线段树成段更新+离散化