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++写法。
具体代码:
View Code
#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;
}
来源:https://www.cnblogs.com/tim11/archive/2012/08/27/2658155.html
