【题目大意】
长度为L的板被分成L段,每段长一个单位长度 (1 <= L <= 100000),
有O个操作 (1 <= O <= 100000)
操作分两种
C A B C 表示将区间[A,B]染成颜色C (1 <= C <= 30)
P A B 输出[A,B]有多少种不同的颜色
开始时[1,L]的颜色为1
【解题思路】
观察颜色的种数最多为30种。因此可以建30颗线段树。tree[x]i表示有无这种颜色i。
【代码】
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int L,T,O;
bool tree[400004][35];
int d[400004];
bool ans[35];
void build_tree(int l,int r,int root)
{
tree[root][1]=true;
if (l==r) return;
int mid=(l+r)/2;
build_tree(l,mid,root*2);
build_tree(mid+1,r,root*2+1);
}
void down(int root)
{
int Lson=root*2;
int Rson=root*2+1;
int sym=d[root];
for (int i=1;i<=T;i++)
{
tree[Lson][i]=false;
tree[Rson][i]=false;
}
tree[Lson][sym]=true;
tree[Rson][sym]=true;
d[root]=0;
d[Lson]=sym;
d[Rson]=sym;
}
void update(int l,int r,int L,int R,int root,int c)
{
if (r<L || l>R) return;
if (l>=L && r<=R)
{
for (int i=1;i<=T;i++)
tree[root][i]=false;
tree[root][c]=true;
d[root]=c;
return;
}
int mid=(l+r)/2;
if (d[root]!=0) down(root);
update(l,mid,L,R,root*2,c);
update(mid+1,r,L,R,root*2+1,c);
for (int i=1;i<=T;i++)
tree[root][i]=(tree[root*2][i] | tree[root*2+1][i]);
}
void query(int l,int r,int L,int R,int root)
{
if (r<L || l>R) return;
if (l>=L && r<=R)
{
for (int i=1;i<=T;i++)
ans[i]=(ans[i] | tree[root][i]);
return;
}
int mid=(l+r)/2;
if (d[root]!=0) down(root);
query(l,mid,L,R,root*2);
query(mid+1,r,L,R,root*2+1);
for (int i=1;i<=T;i++)
tree[root][i]=(tree[root*2][i] | tree[root*2+1][i]);
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%d%d%d",&L,&T,&O);
build_tree(1,L,1);
for (int i=1;i<=O;i++)
{
char ch;
cin>>ch;
if (ch=='C')
{
int A,B,C;
if (A>B) swap(A,B);
scanf("%d%d%d",&A,&B,&C);
update(1,L,A,B,1,C);
}
if (ch=='P')
{
int A,B;
scanf("%d%d",&A,&B);
if (A>B) swap(A,B);
memset(ans,false,sizeof(ans));
query(1,L,A,B,1);
int t=0;
for (int i=1;i<=T;i++)
if (ans[i]) t++;
printf("%d\n",t);
}
}
return 0;
}