题目链接:http://poj.org/problem?id=2777
参考文章:https://blog.csdn.net/heucodesong/article/details/81038360
题目大意:给出T中颜色,可以给一段区域涂色,初始是全为1的颜色,然后有两种操作
(1)C x y z表示将区间x到y的颜色更改为z
(2)P x y 表示查询区间x到y的颜色种类。
题目看起来不符合区间和的条件,但是可以通过二进制转化一下。
初始化肯定都是颜色1,就表示只有一种颜色,然后每次更新颜色时,取这个数的a[x]=1<<(Item-1),a[x]中的1的位置就表示每个颜色的位置
然后pushup操作就改为:a[x]=a[x*2]|a[x*2+1],a[x]中的1的个数就是这个区间颜色的个数。对于Item为什么要-1,其实就是初始颜色时1,就相当于从第0位开始,与数组的0-n-1类似。
(易错:我当时在查询函数中一直出错,但我还没发现,主要是考虑ans1,ans2,ans的初始值是0,这里我已开始写成了1,就错了,
还有ans=ans1|ans2这一步不能少,不然编译会出错,总之,先求出结果再返回。)
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int maxn = 1e5+10; int a[maxn*4],b[maxn*4]; void Init() { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); } void pushup(int x) { a[x]=a[x*2]|a[x*2+1]; } void pushdown(int x) { if(b[x]) { a[x*2]=b[x]; a[x*2+1]=b[x]; b[x*2]=b[x]; b[x*2+1]=b[x]; b[x]=0; } } void build(int x,int l,int r) { if(l==r) { a[x]=1;return ; } int mid=(l+r)/2; build(x*2,l,mid); build(x*2+1,mid+1,r); pushup(x); } void update(int x,int l,int r,int A,int B,int Item) { if(A<=l&&r<=B) { a[x]=1<<(Item-1); b[x]=1<<(Item-1); return ; } int mid=(l+r)/2; pushdown(x); if(A<=mid) update(x*2,l,mid,A,B,Item); if(B>mid) update(x*2+1,mid+1,r,A,B,Item); pushup(x); } int query(int x,int l,int r,int A,int B) { if(A<=l&&r<=B) { return a[x]; } int mid=(l+r)/2; pushdown(x); int ans1=0,ans2=0,ans=0; if(A<=mid) ans1=query(x*2,l,mid,A,B); if(B>mid) ans2=query(x*2+1,mid+1,r,A,B); ans=ans1|ans2; return ans; } int main(void) { int n,m,t,i,x,y,z; while(~scanf("%d%d%d",&n,&t,&m)) { Init(); build(1,1,n); char str[10]; while(m--) { scanf("%s",str); if(str[0]=='C') { scanf("%d%d%d",&x,&y,&z); if(x>y) { int tp=x; x=y; y=tp; } update(1,1,n,x,y,z); } else { scanf("%d%d",&x,&y); if(x>y) { int tp=x; x=y; y=tp; } int cnt=0,ans=query(1,1,n,x,y); while(ans) { if(ans&1) cnt++; ans>>=1; } printf("%d ",cnt); } } } return 0; }