题意很简单了,对一个区间有两种操作:
1. "C A B C" Color the board from segment A to segment B with color C. //A~B涂上颜色C
2. "P A B" Output the number of different colors painted between segment A and segment B (including). //输出A~B间颜色的种类数
题目链接:http://poj.org/problem?id=2777
~~~~
注意到颜色的种类只有30种,由此想到用按位或来合并两个区间的颜色(用一个32位的int型,每一位对应一种颜色),
最后求解所得结果有多少个1就是所求的答案了。
剩下的就是线段树的成段更新了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson rt<<1,s,m
#define rson rt<<1|1,m+1,e
#define N 111111
using namespace std;
int tre[N<<2],vis[N<<2];
void pushup(int rt)
{
tre[rt]=(tre[rt<<1] | tre[rt<<1|1]);
}
void build(int rt,int s,int e)
{
tre[rt]=1;
vis[rt]=0;
if(s==e)
return ;
int m=(s+e)>>1;
build(lson);
build(rson);
pushup(rt);
}
void pushdown(int rt)
{
if(vis[rt])
{
vis[rt<<1]=vis[rt<<1|1]=vis[rt];
tre[rt<<1]=tre[rt<<1|1]=tre[rt];
vis[rt]=0;
}
}
int query(int l,int r,int rt,int s,int e)
{
if(l==s && r==e)
return tre[rt];
pushdown(rt);
int m=(s+e)>>1;
if(r<=m) return query(l,r,lson);
else if(l>m) return query(l,r,rson);
else return (query(l,m,lson) | query(m+1,r,rson));
}
void update(int c,int l,int r,int rt,int s,int e)
{
if(l<=s && r>=e)
{
tre[rt]=c;
vis[rt]=1;
return ;
}
pushdown(rt);
int m=(s+e)>>1;
if(r<=m) update(c,l,r,lson);
else if(l>m) update(c,l,r,rson);
else
{
update(c,l,m,lson);
update(c,m+1,r,rson);
}
pushup(rt);
}
int main()
{
int n,t,m;
while(~scanf("%d%d%d",&n,&t,&m))
{
build(1,1,n);
while(m--)
{
char op[5];
int l,r,c;
scanf("%s",op);
if(op[0]=='C')
{
scanf("%d%d%d",&l,&r,&c);
if(l>r) swap(l,r); //~~
update(1<<(c-1),l,r,1,1,n);
}
else
{
scanf("%d%d",&l,&r);
if(l>r) swap(l,r); //~~
int k=query(l,r,1,1,n);
int ans=0;
do{
if(k&1) ans++; //求解有多少个1.
}while(k>>=1);
printf("%d\n",ans);
}
}
}
return 0;
}