Luogu P1558 色板游戏

题目传送门

此解法超级暴力。洛谷最优解倒数……


因为为这道题只有(30)种颜色,所以我们可以用30颗线段树来分别维护每种颜色。
涂颜色就将对应颜色的线段树区间染色成(1),其他的染成(0)
统计颜色就把线段树都枚举一遍,统计在这个区间上有(1)的线段树数量

然而正解是压位线段树

思路好想,理论时间复杂度也能过,就是常数大,在洛谷不开(O_2)过不去……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
using namespace std;
struct zzz{  //线段树
    int tree[100010<<2],tag[100010<<2];
    void build(int l,int r,int p){
        if(l==r){
            tree[p]=1; return ;
        }
        build(l,mid,ls); build(mid+1,r,rs);
        tree[p]=tree[ls]+tree[rs];
    }
    inline void down(int l,int r,int p){
        if(tag[p]==-1) return ;
        tree[ls]=(mid-l+1)*tag[p];
        tree[rs]=(r-mid)*tag[p];
        tag[ls]=tag[p]; tag[rs]=tag[p]; tag[p]=-1;
    }
    void update(int l,int r,int p,int nl,int nr,int k){
        if(l>=nl&&r<=nr){
            tree[p]=k*(r-l+1); tag[p]=k;
            return ;
        }
        down(l,r,p);
        if(nl<=mid) update(l,mid,ls,nl,nr,k);
        if(nr>mid) update(mid+1,r,rs,nl,nr,k);
        tree[p]=tree[ls]+tree[rs];
    }
    int query(int l,int r,int p,int nl,int nr){
        int ans=0;
        if(l>=nl&&r<=nr) return tree[p];
        down(l,r,p);
        if(nl<=mid) ans+=query(l,mid,ls,nl,nr);
        if(nr>mid) ans+=query(mid+1,r,rs,nl,nr);
        return ans;
    }
}color[31];  //三十颗线段树
inline int read(){
    int k=0,f=1; char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
      if(f=='-') f=-1;
    for(;c>='0'&&c<='9';c=getchar())
      k=k*10+c-48;
    return k*f;
}
inline char read_c(){
    char c=getchar();
    for(;c<'A'||c>'Z';) c=getchar();
    for(;c>='A'&&c<='Z';)
    return c;
}
int main(){
    int n=read(),t=read(),m=read();
    for(int i=1;i<=t;i++) memset(color[i].tag,-1,sizeof(color[i].tag));
    color[1].build(1,n,1);  //初始颜色全为1
    for(int i=1;i<=m;i++){
        char c=read_c();
        if(c=='C'){
            int x=read(),y=read(),z=read();
            if(x>y) x^=y^=x^=y; //x^=y^=x^=y等价于swap(x,y)
            for(int i=1;i<=t;i++){  //涂颜色
                if(i==z) color[i].update(1,n,1,x,y,1);
                else color[i].update(1,n,1,x,y,0);
            }
        }
        else{
            int x=read(),y=read(),anss=0;
            if(x>y) x^=y^=x^=y;
            for(int i=1;i<=t;i++){  //统计颜色
                if(color[i].query(1,n,1,x,y)) ++anss;
            }
            printf("%d
",anss);
        }
    }
    return 0;
}

第十个测试点刚好卡过
卡过

原文地址:https://www.cnblogs.com/morslin/p/11854879.html