题目:
题意:
有
n
n
n个人
k
k
k种蛋糕
会有两种操作,一是将一段区间内的人所拥有的蛋糕类型改为
x
x
x,另一个是询问在
l
∼
r
l\sim r
l∼r共有几种不同的蛋糕种类
分析:
注意到
k
<
=
30
k<=30
k<=30,所以可以用状压来保存蛋糕类型
然后区间操作嘛,自然的线段树
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1; s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0'; s=getchar();}
return d*f;
}
LL ans;
struct Tree{
LL w[400005],lazy[400005];
void pushdown(LL k)
{
if(!lazy[k]) return;
lazy[k]=0;lazy[k*2]=1;lazy[k*2+1]=1;
w[k*2]=w[k*2+1]=w[k];
return;
}
void change(LL k,LL L,LL R,LL l,LL r,LL x)
{
if(l<=L&&R<=r) {w[k]=1<<(x-1);lazy[k]=1;return;}
pushdown(k);
LL mid=(L+R)>>1;
if(mid<l) change(k*2+1,mid+1,R,l,r,x);
else if(mid>=r) change(k*2,L,mid,l,r,x);
else change(k*2,L,mid,l,r,x),change(k*2+1,mid+1,R,l,r,x);
w[k]=w[k*2]|w[k*2+1];
return;
}
void query(LL k,LL L,LL R,LL l,LL r)
{
if(l<=L&&R<=r) {ans|=w[k];return;}
pushdown(k);
LL mid=(L+R)>>1;
if(r<=mid) query(k*2,L,mid,l,r);
else if(mid<l) query(k*2+1,mid+1,R,l,r);
else query(k*2,L,mid,l,r),query(k*2+1,mid+1,R,l,r);
return;
}
}t;
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
LL n=read(),m=read(),k=read();
t.change(1,1,n,1,n,1);
for(LL i=1;i<=m;i++)
{
char c=getchar();
while(c!='C'&&c!='P') c=getchar();
if(c=='C')
{
LL l=read(),r=read(),x=read();
t.change(1,1,n,l,r,x);
}
if(c=='P')
{
LL l=read(),r=read();
ans=0;
t.query(1,1,n,l,r);
LL s=0;
for(LL i=0;i<=30;i++) s+=(ans&(1<<i)?1:0);
printf("%lld\n",s);
}
}
return 0;
}