【POJ 2777 】 线段树之成段更新+位运算
题目链接:http://poj.org/problem?id=2777
题目大意: 给你一段区间[1,L] , 给定初始所有节点颜色为1,有下面两种操作:
1、 “C A B D” 将区间[A,B]改变颜色为D。
2、“P A B” 计算区间[A,B]有多少种不同的颜色。
解题思路:
最土的可能100000个节点*100000次运算,暴力肯定TLE。解决这一类题目一般会想到线段树或者树状数组,这里用线段树。
这里每次改变都从根节点到叶子节点都同步更新的话肯定TLE,这里又要用到区间更新。
区间更新: 区间更新指的是当要改变某个区间[tl,tr]的颜色值,当往下递归到这个区间[l,r]包含在[tl,tr]里面就停止,将要改变的颜色值赋给这个区间,并做一次标记。这个标记的作用防止下次不会再更新这里了,我们查询的时候就可以以标记为判断要不要询问这里的值,而如果下次更新又再次来到这里,就会把先前更新的值给覆盖掉,变为这次更新的值,而与之同步的是上次标记的值会继续往下传,往下传完之后此节点的标记清空。往下传的节点会继续往下传,一直传到此次和上次更新的区间不一样就停止,道理同上。
本题还用到了或位运算。我们用1的个数表示区间不同颜色的种类,则tree[u]=tree[2*u] | tree[2*u+1];
搞错了一下位运算,纠结了良久。 1<<val 往哪边进行位运算1就在哪边。
线段树好题。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cstring> 6 using namespace std; 7 8 const int maxn=100005; 9 int flag[4*maxn]; 10 int tree[4*maxn]; 11 12 void down(int u) ///往下传标记 13 { 14 if(flag[u]) 15 { 16 flag[2*u]=flag[u]; 17 flag[2*u+1]=flag[u]; 18 tree[2*u]=tree[u]; 19 tree[2*u+1]=tree[u]; 20 flag[u]=0; 21 } 22 } 23 24 void build(int u, int l, int r) ///建树 25 { 26 flag[u]=0; 27 tree[u]=(1<<1); 28 if(l==r) 29 return ; 30 int mid=(l+r)>>1; 31 build(2*u,l,mid); 32 build(2*u+1,mid+1,r); 33 } 34 35 void update(int u, int l, int r, int tl, int tr, int val) 36 { 37 if(tl<=l&&r<=tr) 38 { 39 flag[u]=val; 40 tree[u]=(1<<val); ///这里搞错了位运算,写成了(val<<1),纠结了良久 41 return ; 42 } 43 down(u); 44 int mid=(l+r)>>1; 45 if(tr<=mid) update(2*u,l,mid,tl,tr,val); 46 else if(tl>mid) update(2*u+1,mid+1,r,tl,tr,val); 47 else 48 { 49 update(2*u,l,mid,tl,tr,val); 50 update(2*u+1,mid+1,r,tl,tr,val); 51 } 52 tree[u]=tree[2*u]|tree[2*u+1]; 53 } 54 55 int getsum(int u, int l, int r, int tl, int tr) 56 { 57 if(tl<=l&&r<=tr) 58 { 59 return tree[u]; 60 } 61 down(u); 62 int mid=(l+r)>>1; 63 if(tr<=mid) return getsum(2*u,l,mid,tl,tr); 64 else if(tl>mid) return getsum(2*u+1,mid+1,r,tl,tr); 65 else 66 { 67 int t1=getsum(2*u,l,mid,tl,tr); 68 int t2=getsum(2*u+1,mid+1,r,tl,tr); 69 return t1|t2; 70 } 71 } 72 73 int fx(int x) 74 { 75 int ans=0; 76 while(x) 77 { 78 if(x&1) ans++; 79 x>>=1; 80 } 81 return ans; 82 } 83 84 int main() 85 { 86 int n, t, Q; 87 while(~scanf("%d%d%d",&n,&t,&Q)) 88 { 89 build(1,1,n); 90 char ch[3]; 91 while(Q--) 92 { 93 scanf("%s",ch); 94 int l, r, val; 95 if(ch[0]=='C') 96 { 97 scanf("%d%d%d",&l,&r,&val); 98 if(l>r) swap(l,r); 99 update(1,1,n,l,r,val); 100 } 101 else 102 { 103 scanf("%d%d",&l,&r); 104 if(l>r) swap(l,r); 105 int ans=getsum(1,1,n,l,r); 106 printf("%d\n",fx(ans)); 107 } 108 } 109 } 110 return 0; 111 }