POJ 2528 线段树成段更新,数据离散化

来源:互联网 发布:地下停车场出租软件 编辑:程序博客网 时间:2024/06/05 16:07

题意:就是张贴海报,问最后可以看到有多少张海报。因为数据太大,直接建树会爆掉,所以要进行数据离散化。

数据的离散化意思是 比如说我有两张海报,一张从1-1000,另一张从30000-1000000,那我完全可以将第一张看成1-2,第二张看成3-4啊,这样数据量不就减少很多了么。我们只用对所有的点一次快排然后不同的点不断加1就行了,但是单单是这样还是不行,比如1-10,1-3,6-10,这样按照上面的离散化应该是1-4,1-2,3-4,这样结果就变成了2,实际结果应该是3.那我们处理这种数据的话,就是在比较的时候做一个操作,如果两个点的差>1,那我们就将编号的值+2,这样处理上面的数据离散化就变成了1-7,1-3,5-7,这样答案就是正确的了,我的代码离散化是将左端点都变成了负数,右端点为正数,原理类似上面。

#include <stdio.h>#include <algorithm>using namespace std;#define maxn 41000struct tree{int l,r,c;//线段的颜色 }p[maxn<<2];struct node{int point;//记录端点的坐标int num;//记录原来的编号 }line[maxn];int L,R;bool lazy[maxn];//记录颜色是否出现过 int map[maxn][2];//记录输入的线段 int ans;void build(int l,int r,int id){p[id].l=l;p[id].r=r;p[id].c=0;if(l==r)return ;int mid=p[id].l+p[id].r>>1;build(p[id].l,mid,id<<1);build(mid+1,p[id].r,id<<1|1);}void query(int id,int c){if(L<=p[id].l&&p[id].r<=R)//刚好全部覆盖,修改颜色返回 {p[id].c=c;return ;}if(p[id].c>0)//如果当前有颜色,那么就传到左右子树,然后重置0,lazy算法 {p[id<<1].c=p[id<<1|1].c=p[id].c;p[id].c=0;}int mid=p[id].l+p[id].r>>1;if(L<=mid)query(id<<1,c);if(R>mid)query(id<<1|1,c);}void updata(int id){if(p[id].c||p[id].l==p[id].r)//如果当前线段有颜色,记录返回 {if(!lazy[p[id].c]){ans++;lazy[p[id].c]=1;}return ;}//不然就查询左右子树 updata(id<<1);updata(id<<1|1);}bool cmp(node a,node b){return a.point<b.point;}int main(){int t,n,i;scanf("%d",&t);while(t--){scanf("%d",&n);for(i=0;i<n;i++)//离散化{scanf("%d %d",&map[i][0],&map[i][1]);line[2*i].point=map[i][0];line[2*i].num=-(i+1);//线段开头用负数表示 line[2*i+1].point=map[i][1];line[2*i+1].num=i+1;}sort(line,line+2*n,cmp);//重新排序 int res=1;//重新编号int f=line[0].point;for(i=0;i<2*n;i++){if(f!=line[i].point)//如果当前端点和前面的端点不一样,编号值+1{if(line[i].point-f>1)res+=2;//差值大于1,编号值+2else res++;f=line[i].point;}if(line[i].num<0)map[-line[i].num-1][0]=res;else map[line[i].num-1][1]=res;}build(1,res,1);ans=0;memset(lazy,0,sizeof(lazy));lazy[0]=1;for(i=0;i<n;i++){L=map[i][0];R=map[i][1];query(1,i+1);}updata(1);printf("%d\n",ans);}return 0;}



0 0
原创粉丝点击