POJ2777 Count Color 线段树
Description
一个长为L,颜色为1的木板,有操作为
1.C A B C 将[A,B]涂上C颜色
2.P A B 询问[A,b]不同颜色个数。
Input
第一行 L,T,O O为操作个数,T为颜色种类最大个数。
下面O行为操作。
Output
对应询问输出答案。
Sample Input
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
Sample Output
2
1
HINT
对于 100% 的数据,1≤L,O≤100000,1≤O≤30
题解
我们可以用二进制状态压缩,这样就合并区间时同 或 就可以简单合并。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define MAXN 100000+10
using namespace std;
int n,m,t;
int col[MAXN<<2],mark[MAXN<<2];
int cnt(int x)
{
int ans=0;
for(;x;x>>=1)
if(x&1) ans++;
return ans;
}
void pushup(int rt) { col[rt]=col[rt<<1]|col[rt<<1|1];}
void pushdown(int rt)
{
if(mark[rt])
{
mark[rt<<1|1]=mark[rt<<1]=mark[rt];
col[rt<<1|1]=col[rt<<1]=1<<(mark[rt]-1);
mark[rt]=0;
}
}
void build(int rt,int l,int r)
{
if(l==r)
{
mark[rt]=0;col[rt]=1;
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
pushup(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
col[rt]=1<<(c-1);
mark[rt]=c;
return ;
}
int m=(l+r)>>1;
pushdown(rt);
if(L<=m) update(L,R,c,l,m,rt<<1);
if(R>m) update(L,R,c,m+1,r,rt<<1|1);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return col[rt];
pushdown(rt);
int m=(l+r)>>1,ans=0;
if(L<=m) ans|=query(L,R,l,m,rt<<1);
if(m<R) ans|=query(L,R,m+1,r,rt<<1|1);
return ans;
}
int main()
{
while(scanf("%d%d%d",&n,&t,&m)!=EOF)
{
memset(col,0,sizeof(col));
memset(mark,0,sizeof(mark));
build(1,1,n);
char k[3];int a,b,c;
for(int i=1;i<=m;i++)
{
scanf("%s",k);
if(k[0]=='C')
{
scanf("%d%d%d",&a,&b,&c);
if(a>b) swap(a,b);
update(a,b,c,1,n,1);
}else
if(k[0]=='P')
{
scanf("%d%d",&a,&b);
if(a>b) swap(a,b);
printf("%d\n",cnt(query(a,b,1,n,1)));
}
}
}
return 0;
}