POJ2777 - Count Color(区间修改&&懒惰标记&&位运算)
题目大意
给定一个长度为n的序列A,可以对其进行以下两种操作:
1、“C A B C”把区间[A,B]的值全部修改为C
2、“P A B”查询在区间[A,B]中不同的元素总数
题解
每一种颜色的数值用一个2的幂来表示,父节点的值刚好是两个子节点的并操作,答案就是查询的区间值转换成二进制后1的个数,尼玛调试了好久。。被懒惰标记坑了。。。在查询的时候还需要进行更新。。。因为用了懒惰标记,查询的时候有些结点还没有进行更新。。。。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define MAXN 100005 #define lson l , m , s << 1 #define rson m+1 , r , s << 1 | 1 using namespace std; int sumv[MAXN<<2],setv[MAXN<<2]; void PushUp(int s) { sumv[s]=sumv[s<<1]|sumv[s<<1|1]; } void PushDown(int s) { if(setv[s]) { setv[s<<1]=setv[s<<1|1]=setv[s]; sumv[s<<1]=1<<(setv[s]-1); sumv[s<<1|1]=1<<(setv[s]-1); setv[s]=0; } } void build(int l,int r,int s) { sumv[s]=1; setv[s]=0; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int ql,int qr,int d,int l,int r,int s) { if(ql<=l&&r<=qr) { sumv[s]=1<<(d-1); setv[s]=d; return; } PushDown(s); int m=(l+r)>>1; if(ql<=m) update(ql,qr,d,lson); if(qr>m) update(ql,qr,d,rson); PushUp(s); } int query(int ql,int qr,int l,int r,int s) { if((ql<=l&&r<=qr)||setv[s]) return sumv[s]; int m=(l+r)>>1,ans=0; if(ql<=m) ans=ans|query(ql,qr,lson); if(qr>m) ans=ans|query(ql,qr,rson); return ans; } int main(void) { int L,T,p,a,b,c; char ch[5]; while(scanf("%d%d%d",&L,&T,&p)!=EOF) { build(1,L,1); while(p--) { scanf("%s",ch); if(ch[0]=='C') { scanf("%d%d%d",&a,&b,&c); update(a,b,c,1,L,1); } else { scanf("%d%d",&a,&b); int t=query(a,b,1,L,1); int sum=0; while(t) { sum+=(t&1); t=(t>>1); } printf("%d\n",sum); } } } return 0; }