http://poj.org/problem?id=2528
(1)给定一条线段,依次在上面覆盖一些线段(左右位置已给定),求最终能看到的线段数(看到一部分也算)。
本题的本质和染色问题一样,成段染色,延迟更新。
(2)有一个难点在于,所给定的区域是1到1000万,不可能开这么大的数组。况且,用于覆盖的线段只有1万条。
这里用到了离散化方法,简化了问题,压缩了数组的大小(具体情况见代码)。
(3)傻到开了一个pos[]数组,准备用来表示谁映射到谁。。(很无语,当时没有注意pos[]数组要开到1000万这么大)。
(4)在写travel()函数时,忘了加上pushdown()。
(5)思路点拨:
1)映射(离散化),降下内存使用量;
2)染色操作;
3)先消除所有的延迟标记(travel),再计量最终的颜色数,输出结果。
(6)熟悉映射的C++写法。
具体代码:


#include<stdio.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #include<algorithm> #include<vector> #include<map> using namespace std; const int maxn=101000; int t, n, ans; int num[maxn<<2]; int data[maxn]; int mark[maxn], color[maxn<<2]; struct node { int a, b; node(int x, int y) { a=x; b=y; } }; void pushdown(int rt) { if(color[rt]) { color[rt<<1]=color[rt<<1|1]=color[rt]; color[rt]=0; } } void build(int l, int r, int rt) { color[rt]=0; if(l==r) { mark[l]=0; return ; } int m=l+r>>1; build(lson); build(rson); } void update(int L, int R, int i, int l, int r, int rt) { if(L<=l&&r<=R) { color[rt]=i; return ; } pushdown(rt); int m=l+r>>1; if(L<=m) update(L, R, i, lson); if(R>m) update(L, R, i, rson); } void travel(int l, int r, int rt) { if(l==r) { mark[color[rt]]=1; return; } pushdown(rt); int m=l+r>>1; travel(lson); travel(rson); } int main() { while(scanf("%d", &t)!=EOF) { while(t--) { scanf("%d", &n); vector<int>vec; vector<node>v; for(int i=0;i<n;i++) { int x, y; scanf("%d%d", &x, &y); vec.push_back(x); vec.push_back(y); v.push_back(node(x, y)); } sort(vec.begin(), vec.end()); map<int, int>mp; int tm=1; for(int i=0;i<vec.size();i++) { if(mp.find(vec[i])==mp.end()) mp[vec[i]]=tm++; } build(1, n<<1, 1); for(int i=0;i<v.size();i++) { int x, y; x=mp[v[i].a]; y=mp[v[i].b]; update(x, y, i+1, 1, n<<1, 1); } ans=0; travel(1, n<<1, 1); for(int i=1;i<=(n<<1);i++) { if(mark[i]) ans++; } printf("%d\n", ans); } } return 0; }