Count the Colors ZOJ

来源:互联网 发布:傻瓜式淘宝客app 编辑:程序博客网 时间:2024/05/16 11:40

点击打开链接

题意:

在一条长度为8000的线段上染色,每次把区间[a,b]染成c颜色。显然,后面染上去的颜色会覆盖掉之前的颜色。

求染完之后,每个颜色在线段上有多少个间断的区间。

注意: 是在区间上有n段被染色,不是区间右端点为n

思路:
这个题和贴海报的题差不多,都是区间覆盖问题,我们知道涉及到区间覆盖问题 ,那么就是连续型的线段树,
我们又两种处理方法,一种是二分l,r时 在 (l,mid) (mid,r)上递归,这样就成为了连续的了,还有一种处理方法就是将
左端点+1,然后继续是(l,mid) (mid+1,r)仔细体会一下 ,两种方法不一样
处理方法:
这个题要求我们要求的是间断的颜色,为了判断是否间断,我们就如果这个区间(a,b)要染色,那么我们就标记区间内
所有的点,最后以点的颜色来判断是否是间断的

左端点+1代码:
#include<iostream>#include<cstdio>  #include<cstring>  using namespace std;const int maxn=8005;typedef long long ll;int n;int ans[4*maxn],book[4*maxn];int laz[4*maxn];void pushdown(int d){if(laz[d]!=-1){laz[2*d]=laz[2*d+1]=laz[d];laz[d]=-1;}}void update(int l,int r,int L,int R,int val,int d){if(L<=l&&r<=R){laz[d]=val;return ;}if(laz[d]==val)return ;pushdown(d);int mid=(l+r)/2;if(L<=mid)update(l,mid,L,R,val,2*d);if(R>mid)update(mid+1,r,L,R,val,2*d+1);return ;}void query(int l,int r,int d){if(laz[d]>=0){for(int i=l;i<=r;i++)book[i]=laz[d];return ;}int mid=(l+r)/2;if(l!=r){query(l,mid,2*d);query(mid+1,r,2*d+1);}return ;}int main(){int i,j;int a,b,c;while(scanf("%d",&n)!=EOF){memset(laz,-1,sizeof(laz));memset(ans,0,sizeof(ans));for(i=0;i<n;i++){scanf("%d%d%d",&a,&b,&c);if(a>=b)continue;update(1,8000,a+1,b,c,1);}memset(book,-1,sizeof(book));query(1,8000,1);i=1;while(i<maxn){int col=book[i];if(col==-1){i++;continue;}j=i+1;while(book[j]!=-1&&col==book[j]&&j<maxn){j++;}ans[col]++;i=j;}for(i=0;i<=maxn;i++)if(ans[i]!=0)printf("%d %d\n",i,ans[i]);printf("\n");} return 0;}#include<bits/stdc++.h>using namespace std;const int maxn=1e6+10;typedef long long ll;int main(){ return 0;}

按照连续型来处理:
按照连续型来处理有很多需要注意的地方,你比如当左右区间相等时如果不返回,就会一直递归进入死循环,
而且如果左右区间相等,由于我们找的是间断的颜色所以最后一个点也要染色,因为我们标记的区间上的点
#include<iostream>#include<cstdio>  #include<cstring>  using namespace std;const int maxn=8005;typedef long long ll;int n;int ans[4*maxn],book[4*maxn];int laz[4*maxn];void pushdown(int d){if(laz[d]!=-1){laz[2*d]=laz[2*d+1]=laz[d];laz[d]=-1;}}void update(int l,int r,int L,int R,int val,int d){if(L<=l&&r<=R){laz[d]=val;return ;}int mid=(l+r)/2;if(l==mid){ return ;}pushdown(d);if(L<=mid)update(l,mid,L,R,val,2*d);if(R>mid)update(mid,r,L,R,val,2*d+1);return ;}void query(int l,int r,int d){if(laz[d]>=0){for(int i=l;i<=r;i++)book[i]=laz[d];return ;}int mid=(l+r)/2;if(l==mid)//防止死循环,因为这样分有可能一直递归下去,而且需要注意的是当只有一个点的时候也要染色!{book[l]=laz[d]; return ; }if(l!=r){query(l,mid,2*d);query(mid,r,2*d+1);}return ;}int main(){int i,j;int a,b,c;while(scanf("%d",&n)!=EOF){memset(laz,-1,sizeof(laz));memset(ans,0,sizeof(ans));for(i=0;i<n;i++){scanf("%d%d%d",&a,&b,&c);if(a>=b)continue;update(1,8001,a+1,b+1,c,1);}memset(book,-1,sizeof(book));query(1,8001,1);i=1;while(i<maxn){int col=book[i];if(col==-1){i++;continue;}j=i+1;while(book[j]!=-1&&col==book[j]&&j<maxn){j++;}ans[col]++;i=j;}for(i=0;i<=maxn;i++)if(ans[i]!=0)printf("%d %d\n",i,ans[i]);printf("\n");} return 0;}

另外多说几句:
对于这种类似于海报的区间覆盖问题,也有很多的不一样,因为我看我舍友做的POJ上的海报问题它是把一个点
表示了一个区间,这样就是一个离散型的线段树而不是连续型的线段树了,两种做法结果会不一样


0 0
原创粉丝点击