此解法超级暴力。洛谷最优解倒数……
因为为这道题只有\(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\n",anss); } } return 0; }
第十个测试点刚好卡过
