【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 }

 

 

posted @ 2012-12-18 20:56  Mr. Ant  阅读(468)  评论(0编辑  收藏  举报