题目链接:http://poj.org/problem?id=2777
题目大意:一个长为L的线段,两种操作:“C a b c”表示将区间[a,b]染成颜色c,“P a b”输出区间[a,b]内一共有多少种不同的颜色。
分析:很裸的线段树区间操作的题,注意到颜色种类一共不超过30种,我们可以把它对应到二进制中的每一位。
实现代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=1e5+10;
struct segment
{
int l,r;
int c; //表示该区间的染色
bool cov; //表示区间是否为纯色
int mid()
{
return (l+r)>>1;
}
}tree[M<<2];
void build(int rt,int l,int r)
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].c=1;
tree[rt].cov=false;
if(l==r) return ;
int m=tree[rt].mid();
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
}
void update(int rt,int l,int r,int c)
{
if(tree[rt].l==l&&tree[rt].r==r)
{
tree[rt].cov=false;
tree[rt].c=(1<<(c-1));
return ;
}
if(!tree[rt].cov)
{
tree[rt<<1].c=tree[rt<<1|1].c=tree[rt].c;
tree[rt].cov=true;
tree[rt<<1].cov=tree[rt<<1|1].cov=false;
}
int m=tree[rt].mid();
if(r<=m) update(rt<<1,l,r,c);
else if(l>m) update(rt<<1|1,l,r,c);
else
{
update(rt<<1,l,m,c);
update(rt<<1|1,m+1,r,c);
}
tree[rt].c=tree[rt<<1].c|tree[rt<<1|1].c;
}
int query(int rt,int l,int r)
{
if(!tree[rt].cov||(tree[rt].l==l&&tree[rt].r==r))
return tree[rt].c;
int m=tree[rt].mid();
if(r<=m) return query(rt<<1,l,r);
else if(l>m) return query(rt<<1|1,l,r);
else return query(rt<<1,l,m)|query(rt<<1|1,m+1,r);
}
int count(int x)
{
int num=0;
while(x)
{
x=x&(x-1);
num++;
}
return num;
}
int main()
{
int n,t,op;
while(scanf("%d%d%d",&n,&t,&op)!=-1)
{
build(1,1,n);
while(op--)
{
char ch[5];
int a,b,c;
scanf("%s",ch);
if(ch[0]=='C')
{
scanf("%d%d%d",&a,&b,&c);
if(a>b) swap(a,b);
update(1,a,b,c);
}
else
{
scanf("%d%d",&a,&b);
if(a>b) swap(a,b);
int ans=query(1,a,b);
printf("%d\n",count(ans));
}
}
}
return 0;
}