【NOIP模拟】颜料大乱斗

Description

【NOIP模拟】颜料大乱斗_第1张图片

Solution

开始看到前面的题目那么水,到这题时就开始胡思乱想了,待修改莫队?树套树?30棵线段树?
然后我打了30棵线段树,常数十分的大啊!
超时30分TAT。
然后旁边的人把30个颜色的值放到同一个节点上,然后就对了,?????
常数小而已嘛!
虽然两个方法的时间复杂度理论上是一样的。
其实就是每个节点存储30个颜色是否出现过,然后两个儿子向上合并就好了。

Code

#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);
        }
    }
}

你可能感兴趣的:(noip,线段树,暴搜,可持久化线段树)