[luogu1558][POJ2777]Count Color(线段树+二进制操作)

来源:互联网 发布:react 源码 component 编辑:程序博客网 时间:2024/06/03 16:28

题目:我是超链接

题解:

首先这题与最传统线段树区别在于:统计区间不同数字个数。不过你可以看到修改的颜色是连续的,且不超过30.这就非常好办了,直接状态压缩要修改的颜色。然后线段树上把左右孩子按位或起来便是。最后区间答案中转成二进制里“1”的个数便是不同数字个数。

代码:

#include <cstdio>#include <iostream>#include <cstring>using namespace std;int sum[400005],delta[400005];void updata(int now){sum[now]=(sum[now<<1]|sum[now<<1|1]);}void build(int now,int l,int r){if (l==r) {sum[now]=1;return;}int mid=(l+r)>>1;if (l<=mid) build(now<<1,l,mid);if (r>mid) build(now<<1|1,mid+1,r);updata(now);}void pushdown(int now){if (delta[now]){delta[now<<1]=delta[now]; delta[now<<1|1]=delta[now];sum[now<<1]=delta[now]; sum[now<<1|1]=delta[now];delta[now]=0;}}void change(int now,int l,int r,int lrange,int rrange,int k){if (lrange<=l && rrange>=r){sum[now]=k; delta[now]=k;return;}    int mid=(l+r)>>1;pushdown(now);    if (lrange<=mid) change(now<<1,l,mid,lrange,rrange,k);    if (rrange>mid) change(now<<1|1,mid+1,r,lrange,rrange,k);    updata(now);}  int qurry(int now,int l,int r,int lrange,int rrange){if (lrange<=l && rrange>=r) return sum[now];pushdown(now);//这个pushdown如果加在外面就会越界GG    int mid=(l+r)>>1,ans=0;    if (lrange<=mid) ans|=qurry(now<<1,l,mid,lrange,rrange);    if (rrange>mid) ans|=qurry(now<<1|1,mid+1,r,lrange,rrange);    updata(now);    return ans;}  int main(){int l,t,o,i,a,b,c;scanf("%d%d%d",&l,&t,&o);build(1,1,l);for (i=1;i<=o;i++){char s[5];scanf("%s%d%d",s,&a,&b);if (a>b) swap(a,b);if (s[0]=='C'){scanf("%d",&c);change(1,1,l,a,b,1<<c-1);}else{int ans=0;int v=qurry(1,1,l,a,b);while (v){ans+=v&1; v>>=1;}printf("%d\n",ans);}}}