来源:http://poj.org/problem?id=2777
题意:有一个区间,最多有30种颜色。有两种操作,一种是对某一个区间段染上某一种颜色,一种是询问该区间有多少种不同的颜色。
思路:线段树的好题,线段树 + lazy思想的经典应用。而且和位运算结合到了一起。因为颜色数量很少,而且父结点的颜色正好是两个子结点颜色的按位或,因此可以用位运算。最后1的个数就是不同颜色的个数。
ac代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int N=100010;
struct tree{
int left,right,numcol;
bool cover;
}tt[N*4];
int len,numcolour,numop,x,y;
void build_tree(int lp,int rp,int pos){
tt[pos].left=lp;
tt[pos].right=rp;
tt[pos].numcol=(1<<1);
tt[pos].cover=true;
if(lp==rp)return;
int mid=(lp+rp)/2;
build_tree(lp,mid,pos*2);
build_tree(mid+1,rp,pos*2+1);
}
void add(int lp,int rp,int id,int pos){
if(lp<=tt[pos].left&&rp>=tt[pos].right){
tt[pos].cover=true;
tt[pos].numcol=(1<<id);
return;
}
if(tt[pos].cover){
tt[pos*2].cover=true;
tt[pos*2+1].cover=true;
tt[pos*2].numcol=tt[pos].numcol;
tt[pos*2+1].numcol=tt[pos].numcol;
tt[pos].cover=false;
}
int mid=(tt[pos].left+tt[pos].right)/2;
if(lp<=mid)
add(lp,rp,id,pos*2);
if(rp>mid)
add(lp,rp,id,pos*2+1);
tt[pos].numcol=tt[pos*2].numcol|tt[pos*2+1].numcol;
}
int query(int lp,int rp,int pos){
if(tt[pos].left==lp&&tt[pos].right==rp){
return tt[pos].numcol;
}
if(tt[pos].cover){
tt[2*pos].cover=true;
tt[2*pos+1].cover=true;
tt[2*pos].numcol=tt[pos].numcol;
tt[2*pos+1].numcol=tt[pos].numcol;
tt[pos].cover=false;
}
int mid=(tt[pos].left+tt[pos].right)/2;
if(lp>mid)
return query(lp,rp,pos*2+1);
else if(rp<=mid)
return query(lp,rp,pos*2);
else
return query(lp,mid,pos*2)|query(mid+1,rp,pos*2+1);
}
int fenjie(int x){
int ans=0;
while(x){
if(x%2)
ans++;
x/=2;
}
return ans;
}
int main(){
//freopen("1.txt","r",stdin);
while(~scanf("%d%d%d",&len,&numcolour,&numop)){
build_tree(1,len,1);
char ss[2];
int id;
while(numop--){
scanf("%s",ss);
if(ss[0]=='C'){
scanf("%d%d%d",&x,&y,&id);
if(x>y)
swap(x,y);
add(x,y,id,1);
}
else{
scanf("%d%d",&x,&y);
if(x>y)
swap(x,y);
int sum=query(x,y,1);
int total=fenjie(sum);
printf("%d\n",total);
}
}
}
return 0;
}