POJ 2777 线段树+lazy思想 + 染色问题_codestorm_新浪博客

本文介绍了一道关于线段树的经典题目,利用线段树进行区间染色及查询不同颜色数量的操作,并通过懒惰传播减少重复计算,巧妙地运用位运算提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.youkuaiyun.com/wmn_wmn/article/details/7468845


题意:有一个区间,最多有30种颜色。有两种操作,一种是对某一个区间段染上某一种颜色,一种是询问该区间有多少种不同的颜色。

思路:线段树的好题,线段树 + lazy思想的经典应用。而且和位运算结合到了一起。因为颜色数量很少,而且父结点的颜色正好是两个子结点颜色的按位或,因此可以用位运算。最后1的个数就是不同颜色的个数。

ac代码:

 

[cpp]  view plain copy
  1. #include   
  2. #include   
  3. using namespace std;  
  4. const int N=100010;  
  5. struct tree{  
  6.     int left,right,numcol;  
  7.     bool cover;  
  8. }tt[N*4];  
  9. int len,numcolour,numop,x,y;  
  10. void build_tree(int lp,int rp,int pos){  
  11.     tt[pos].left=lp;  
  12.     tt[pos].right=rp;  
  13.     tt[pos].numcol=(1<<1);  
  14.     tt[pos].cover=true;  
  15.     if(lp==rp)return;  
  16.     int mid=(lp+rp)/2;  
  17.     build_tree(lp,mid,pos*2);  
  18.     build_tree(mid+1,rp,pos*2+1);  
  19. }  
  20. void add(int lp,int rp,int id,int pos){  
  21.     if(lp<=tt[pos].left&&rp>=tt[pos].right){  
  22.         tt[pos].cover=true;  
  23.         tt[pos].numcol=(1<<id);  
  24.         return;  
  25.     }  
  26.     if(tt[pos].cover){  
  27.         tt[pos*2].cover=true;  
  28.         tt[pos*2+1].cover=true;  
  29.         tt[pos*2].numcol=tt[pos].numcol;  
  30.         tt[pos*2+1].numcol=tt[pos].numcol;  
  31.         tt[pos].cover=false;  
  32.     }  
  33.     int mid=(tt[pos].left+tt[pos].right)/2;  
  34.     if(lp<=mid)  
  35.         add(lp,rp,id,pos*2);  
  36.     if(rp>mid)  
  37.         add(lp,rp,id,pos*2+1);  
  38.     tt[pos].numcol=tt[pos*2].numcol|tt[pos*2+1].numcol;  
  39. }  
  40. int query(int lp,int rp,int pos){  
  41.     if(tt[pos].left==lp&&tt[pos].right==rp){  
  42.         return tt[pos].numcol;  
  43.     }  
  44.     if(tt[pos].cover){  
  45.         tt[2*pos].cover=true;  
  46.         tt[2*pos+1].cover=true;  
  47.         tt[2*pos].numcol=tt[pos].numcol;  
  48.         tt[2*pos+1].numcol=tt[pos].numcol;  
  49.         tt[pos].cover=false;  
  50.     }  
  51.     int mid=(tt[pos].left+tt[pos].right)/2;  
  52.     if(lp>mid)  
  53.         return query(lp,rp,pos*2+1);  
  54.     else if(rp<=mid)  
  55.         return query(lp,rp,pos*2);  
  56.     else  
  57.         return query(lp,mid,pos*2)|query(mid+1,rp,pos*2+1);  
  58. }  
  59. int fenjie(int x){  
  60.     int ans=0;  
  61.     while(x){  
  62.       if(x%2)  
  63.           ans++;  
  64.       x/=2;  
  65.     }  
  66.     return ans;  
  67. }  
  68. int main(){  
  69.     //freopen("1.txt","r",stdin);  
  70.     while(~scanf("%d%d%d",&len,&numcolour,&numop)){  
  71.       build_tree(1,len,1);  
  72.       char ss[2];  
  73.       int id;  
  74.       while(numop--){  
  75.         scanf("%s",ss);  
  76.         if(ss[0]=='C'){  
  77.           scanf("%d%d%d",&x,&y,&id);  
  78.           if(x>y)  
  79.               swap(x,y);  
  80.           add(x,y,id,1);  
  81.         }  
  82.         else{  
  83.           scanf("%d%d",&x,&y);  
  84.           if(x>y)  
  85.               swap(x,y);  
  86.           int sum=query(x,y,1);  
  87.           int total=fenjie(sum);  
  88.           printf("%d\n",total);  
  89.         }  
  90.       }  
  91.     }  
  92.     return 0;  
  93. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值