开始看到前面的题目那么水,到这题时就开始胡思乱想了,待修改莫队?树套树?30棵线段树?
然后我打了30棵线段树,常数十分的大啊!
超时30分TAT。
然后旁边的人把30个颜色的值放到同一个节点上,然后就对了,?????
常数小而已嘛!
虽然两个方法的时间复杂度理论上是一样的。
其实就是每个节点存储30个颜色是否出现过,然后两个儿子向上合并就好了。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int i,j,k,l,n,m;
int a,b,c,d,num;
struct node{
int add;
int son[31];
}t[100007*3],ans,p;
char s[10];
void down(int x,int l,int r){
if(l==r)return;
int mid=(l+r)/2;
if(t[x].add){
t[x*2].add=t[x].add,t[x*2+1].add=t[x].add;
int i;
fo(i,1,c)t[x*2].son[i]=t[x*2+1].son[i]=t[x].son[i];
t[x].add=0;
}
}
node merge(node x,node y){
int i;
node z;memset(z.son,0,sizeof(z.son));
fo(i,1,c)z.son[i]=x.son[i]|y.son[i];
return z;
}
void change(int x,int l,int r,int y,int z,int o){
down(x,l,r);
if(l==y&&r==z){
memset(t[x].son,0,sizeof(t[x].son));
t[x].son[o]=1;
t[x].add=o;
return;
}
int mid=(l+r)/2;
if(z<=mid)change(x*2,l,mid,y,z,o);
else if(y>mid)change(x*2+1,mid+1,r,y,z,o);
else{
change(x*2,l,mid,y,mid,o);
change(x*2+1,mid+1,r,mid+1,z,o);
}
int i;
fo(i,1,c)t[x].son[i]=t[x*2].son[i]|t[x*2+1].son[i];
}
node find(int x,int l,int r,int y,int z){
down(x,l,r);
if(l==y&&r==z){
int i,o=0;
return t[x];
}
int mid=(l+r)/2;
if(z<=mid)return find(x*2,l,mid,y,z);
else if(y>mid)return find(x*2+1,mid+1,r,y,z);
else{
node q;memset(q.son,0,sizeof(q.son));
q=merge(find(x*2,l,mid,y,mid),find(x*2+1,mid+1,r,mid+1,z));
return q;
}
}
int main(){
// freopen("fan.in","r",stdin);
// freopen("fan.out","w",stdout);
scanf("%d%d%d",&n,&c,&m);
change(1,1,n,1,n,1);
while(m--){
scanf("%s%d%d",s,&a,&b);
if(a>b)swap(a,b);
if(s[0]=='C'){
scanf("%d",&d);
change(1,1,n,a,b,d);
}
else{
if(a>b)swap(a,b);
ans=find(1,1,n,a,b);
int o=0;
fo(i,1,30)if(ans.son[i])o++;
printf("%d\n",o);
}
}
}