您的位置:首页 > 其它

poj2777 Count Color

2016-02-14 23:40 281 查看
这种线段树不是一个点一个点更新的 是一段一段来更新的

颜色只有30种,可以使用位运算 & 和 | 的巧妙

poj再次坑人,区间左大右小的情况,好气啊

#include<cstdio>
#include<iostream>
const int inf=0x3f3f3f3f;
const int maxn=300005;
struct note{
int l,r,color;
bool cover;///表示是否覆盖了l-r
}a[(maxn<<2)];

int n,c,m;
void init_(int i,int l,int r){
a[i].l=l;
a[i].r=r;
a[i].color=1<<1;
a[i].cover=true;///覆盖了
if(l==r)return ;
int mid=(l+r)>>1;
init_(i<<1,l,mid);
init_(i<<1 |1,mid+1,r);
a[i].color=a[i<<1].color|a[i<<1 |1].color;
}
int calc(int i,int l,int r){
if(a[i].l==l&&a[i].r==r)return a[i].color;
if(a[i].cover){///在这里统计的时候 这个区间是覆盖的 那么你需要展开
a[i].cover=false;
a[i<<1].cover=a[i<<1 |1].cover=true;
a[i<<1].color=a[i<<1 |1].color=a[i].color;
}
int mid=(a[i].l+a[i].r)>>1;///这里的l r
///a[i].l a[i].r
///都是概念不一样的 一开始这里写的 l r是错的
if(l>mid)return calc(i<<1 |1,l,r);
else if(r<=mid)return calc(i<<1,l,r);
return calc(i<<1,l,mid)|calc(i<<1 |1,mid+1,r);
}
int color_;
void updata(int i,int l,int r){
if(a[i].l==l&&a[i].r==r){///成端更新一个区间 而不是一个点一个点去更新
a[i].color=color_;
a[i].cover=true;
return ;
}
if(a[i].cover){///需要从这里更新的时候 需要更新的可能只是你这个区间的一部分 所以把上次更新的展开
a[i].cover=false;
a[i<<1].cover=a[i<<1 |1].cover=true;
a[i<<1].color=a[i<<1 |1].color=a[i].color;
}
int mid=(a[i].l+a[i].r)>>1;///这里的l r
///a[i].l a[i].r
///都是概念不一样的 一开始这里写的 l r是错的
if(l>mid) updata(i<<1 |1,l,r);
else if(r<=mid) updata(i<<1,l,r);
else{
updata(i<<1,l,mid);
updata(i<<1 |1,mid+1,r);
}
a[i].color=a[i<<1].color|a[i<<1 |1].color;
}

void scanf_(char &data){
while((data=getchar())&&(data!='P'&&data!='C')){
}
}
int main(){
while(scanf("%d%d%d",&n,&c,&m)!=-1){
init_(1,1,n);
while(m--){
char ch;
int aa,bb,cc;
scanf_(ch);
if(ch=='P'){
scanf("%d%d",&aa,&bb);
if(aa>bb)aa^=bb^=aa^=bb;///好气人啊  区间还有左大右小的
int ans=calc(1,aa,bb);/// aa bb
int sum=0;
while(ans){
sum+=(ans&1);
ans>>=1;
}
printf("%d\n",sum);
}
else{
scanf("%d%d%d",&aa,&bb,&cc);
if(aa>bb)
aa^=bb^=aa^=bb;
color_=1<<cc;
updata(1,aa,bb);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: