luogu P1558 色板遊戲
阿新 • • 發佈:2019-02-14
題意:
有n個位置,每一個位置都有一個顏色,初始顏色為1。現在有兩個操作:
[1]將x~y區間的顏色改為z;
[2]統計x~y區間不同顏色數的個數。
思路:
考慮用一顆線段樹來維護這一些操作,發現統計顏色好像做不到,就可以想到顏色的範圍<31,所以考慮狀態壓縮。用一個30位的數來表示當前的顏色,如1表示為1,2表示為10,以此類推,用一個異或搞一個改段求段即可。
程式碼:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m,q,len=0; struct node{int d,lazy,l,r,lc,rc;} tr[200010]; void build(int l,int r) { int now=++len,mid=(l+r)>>1; tr[now].l=l; tr[now].r=r; tr[now].d=1; tr[now].lazy=0; tr[now].lc=tr[now].rc=-1; if(l<r) { tr[now].lc=len+1; build(l,mid); tr[now].rc=len+1; build(mid+1,r); } } void updata(int x) { if(tr[x].lazy) { int lc=tr[x].lc,rc=tr[x].rc; tr[lc].lazy=tr[rc].lazy=tr[x].lazy; tr[lc].d=tr[rc].d=tr[x].lazy; tr[x].lazy=0; } } void change(int now,int l,int r,int k) { updata(now); if(l==tr[now].l&&r==tr[now].r) { tr[now].d=k; tr[now].lazy=k; return; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1; if(r<=mid) change(lc,l,r,k); else if(l>mid) change(rc,l,r,k); else change(lc,l,mid,k),change(rc,mid+1,r,k); tr[now].d=tr[lc].d|tr[rc].d; } int findsum(int now,int l,int r) { updata(now); if(l==tr[now].l&&r==tr[now].r) return tr[now].d; int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1; if(r<=mid) return findsum(lc,l,r); else if(l>mid) return findsum(rc,l,r); else return findsum(lc,l,mid)|findsum(rc,mid+1,r); } int work(int x) { int sum=0; while(x>0) { sum+=(x&1); x>>=1; } return sum; } int main() { char s[5]; int x,y,z; scanf("%d %d %d",&n,&m,&q); build(1,n); for(int i=1;i<=q;i++) { scanf("%s",s+1); if(s[1]=='C') { scanf("%d %d %d",&x,&y,&z); if(x>y) swap(x,y); change(1,x,y,1<<(z-1)); } else { scanf("%d %d",&x,&y); if(x>y) swap(x,y); printf("%d\n",work(findsum(1,x,y))); } } }