洛谷 1558 色板游戏
【题解】
容易想到用线段树维护,但是无脑开T棵线段树会导致时间超限。怎么办呢?我们可以把一个区间的状态用30位2进制数表示。第$i$位为$1$表示这个区间有第$i$种颜色,为$0$表示没有。
这样我们只需要维护区间或的结果,并支持区间设为一个数即可。
1 #include<cstdio> 2 #include<algorithm> 3 #define ls (u<<1) 4 #define rs (u<<1|1) 5 #define mid ((a[u].l+a[u].r)>>1) 6 using namespace std; 7 int n,m,c,l,r,col,exp[100]; 8 struct tree{ 9 int l,r,sum,same; 10 }a[400010]; 11 inline int read(){ 12 int k=0,f=1; char c=getchar(); 13 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 14 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 15 return k*f; 16 } 17 void build(int u,int l,int r){ 18 a[u].l=l; a[u].r=r; a[u].sum=1; a[u].same=0; 19 if(l<r) build(ls,l,mid),build(rs,mid+1,r); 20 } 21 void pushup(int u){a[u].sum=a[ls].sum|a[rs].sum;} 22 void pushdown(int u){ 23 if(!a[u].same) return; a[u].same=0; 24 a[ls].same=a[rs].same=1; 25 a[ls].sum=a[rs].sum=a[u].sum; 26 } 27 void setsame(int u,int l,int r,int c){ 28 if(l<=a[u].l&&a[u].r<=r){ 29 a[u].same=1; a[u].sum=exp[c]; return; 30 } 31 pushdown(u); 32 if(l<=mid) setsame(ls,l,r,c); 33 if(r>mid) setsame(rs,l,r,c); 34 pushup(u); 35 } 36 int query(int u,int l,int r){ 37 if(l<=a[u].l&&a[u].r<=r) return a[u].sum; 38 pushdown(u); int ret=0; 39 if(l<=mid) ret=query(ls,l,r); 40 if(r>mid) ret=ret|query(rs,l,r); 41 return ret; 42 } 43 int main(){ 44 n=read(); c=read(); m=read(); build(1,1,n); 45 exp[1]=1; 46 for(int i=2;i<=c;i++) exp[i]=exp[i-1]<<1; 47 //for(int i=1;i<=c;i++) printf("%d ",exp[i]); puts(""); 48 while(m--){ 49 char ch=getchar(); 50 while(ch!='P'&&ch!='C') ch=getchar(); 51 if(ch=='C'){ 52 l=read(); r=read(); col=read(); 53 if(l>r) swap(l,r); 54 setsame(1,l,r,col); 55 } 56 else{ 57 l=read(); r=read(); 58 if(l>r) swap(l,r); 59 int ans=0,tmp=query(1,l,r); 60 //printf("tmp=%d ",tmp); 61 for(int i=c;i>=1;i--) if(tmp>=exp[i]) ans++,tmp-=exp[i]; 62 printf("%d\n",ans); 63 } 64 } 65 return 0; 66 }