睡覺困難綜合徵 樹鏈剖分
阿新 • • 發佈:2018-12-21
睡覺困難綜合徵
樹剖好題。
做這道題之前,請先做一做[NOI2014]起床困難綜合症。記得我在我的樹鏈剖分總結中的第一句話嗎?這道題就是那道的上樹帶修版本。
首先簡單口胡一下起床困難綜合症:只需要把每一位初始狀態為零和為一的結果預處理出來,這個過程可以通過把\(0\)和\(inf\)進行一遍題目中要求的操作來得到;然後從高位往低位貪心即可。
上樹帶修之後就考慮用線段樹維護上面預處理的結果。線段樹維護四個值:
從左往右\(0\)通過的結果:\(f[0][0]\);
從左往右\(inf\)通過的結果:\(f[0][1]\);
從右往左\(0\)通過的結果:\(f[1][0]\)
從右往左\(inf\)通過的結果:\(f[1][1]\)。
當兩個區間合併時,設左區間為\(p\),右區間為\(q\),合併後的區間為\(k\),以\(k[0][0]\)的合併為例:若要使\(k[0][0]\)的某一位為\(1\),要麼\(p[0][0]\)和\(q[0][1]\)同時為\(1\),要麼\(p[0][0]\)為\(0\)且\(q[0][1]\)為\(1\)。這個結論請自己手玩證明,對於其他資訊的合併也可以使用同樣的方式推導。
在修改時,直接線上段樹上更改某個點的值就好了。對於每一個詢問,可以使用上面合併區間的方法合併重鏈上的資訊,合併時注意誰是左區間誰右區間,從線段樹上得到資訊之後就按照區間上的做法一遍貪心得到答案。
注意必須使用unsigned long long。程式碼不長(2.9K),實現起來細節很多。
#include<cstdio> #include<cctype> #define R register #define I inline #define L unsigned long long using namespace std; const int S=100003,N=200003,M=400003; const L inf=-1; char buf[1000000],*p1,*p2; I char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,S,stdin),p1==p2)?EOF:*p1++;} I L rd(){ L f=0; R char c=gc(); while(c<48||c>57) c=gc(); while(c>47&&c<58) f=f*10+(c^48),c=gc(); return f; } int h[S],s[N],g[N],d[S],t[S],p[S],q[S],f[S],r[S],a[S],u[S],n,k,c; L b[S],v[S]; struct E{ L a[2][2]; E(){a[0][0]=a[1][0]=0,a[0][1]=a[1][1]=inf;} I L* operator[](int x){return a[x];} I E operator+(E y){ E x=*this,o; o[0][0]=(x[0][0]&y[0][1])|((~x[0][0])&y[0][0]); o[0][1]=(x[0][1]&y[0][1])|((~x[0][1])&y[0][0]); o[1][0]=(y[1][0]&x[1][1])|((~y[1][0])&x[1][0]); o[1][1]=(y[1][1]&x[1][1])|((~y[1][1])&x[1][0]); return o; } }e[M]; I void swp(L&x,L&y){x^=y,y^=x,x^=y;} I void add(int x,int y){s[++c]=h[x],h[x]=c,g[c]=y;} void dfs1(int x,int f){ p[x]=f,d[x]=d[f]+1,t[x]=1; for(R int i=h[x],y,m=0;i;i=s[i]) if((y=g[i])^f){ dfs1(y,x),t[x]+=t[y]; if(t[y]>m) q[x]=y,m=t[y]; } } void dfs2(int x,int t){ f[x]=++c,r[x]=t,u[c]=a[x],v[c]=b[x]; if(!q[x]) return; dfs2(q[x],t); for(R int i=h[x],y;i;i=s[i]) if((y=g[i])^p[x]&&y^q[x]) dfs2(y,y); } I void upd(int k,int x,L y){ if(x==1) e[k][0][0]=e[k][1][0]=0,e[k][0][1]=e[k][1][1]=y; if(x==2) e[k][0][0]=e[k][1][0]=y,e[k][0][1]=e[k][1][1]=inf; if(x==3) e[k][0][0]=e[k][1][0]=y,e[k][0][1]=e[k][1][1]=inf^y; } I void psu(int k,int p,int q){e[k]=e[p]+e[q];} void bld(int k,int l,int r){ if(l==r){ upd(k,u[l],v[l]); return ; } R int p=k<<1,q=p|1,m=l+r>>1; bld(p,l,m),bld(q,m+1,r),psu(k,p,q); } void mdf(int k,int l,int r,int x,int y,L z){ if(l==r){ upd(k,y,z); return ; } R int p=k<<1,q=p|1,m=l+r>>1; if(x<=m) mdf(p,l,m,x,y,z); else mdf(q,m+1,r,x,y,z); psu(k,p,q); } E qry(int k,int l,int r,int x,int y){ if(x<=l&&r<=y) return e[k]; R int p=k<<1,q=p|1,m=l+r>>1; E o; if(x<=m) o=o+qry(p,l,m,x,y); if(m<y) o=o+qry(q,m+1,r,x,y); return o; } L qry0(int x,int y,L z){ E t,u,v; L o=0; while(r[x]^r[y]) if(d[r[x]]>d[r[y]]){ t=qry(1,1,n,f[r[x]],f[x]),swp(t[0][0],t[1][0]),swp(t[0][1],t[1][1]); u=u+t,x=p[r[x]]; } else v=qry(1,1,n,f[r[y]],f[y])+v,y=p[r[y]]; if(d[x]>d[y]) t=qry(1,1,n,f[y],f[x]),swp(t[0][0],t[1][0]),swp(t[0][1],t[1][1]),u=u+t+v; else u=u+qry(1,1,n,f[x],f[y])+v; for(R int i=k-1;~i;--i) if(u[0][0]>>i&1) o+=1llu<<i; else if((u[0][1]>>i)&1&&1llu<<i<=z) o+=1llu<<i,z-=1llu<<i; return o; } int main(){ R int m,i,o,x,y; L z; n=rd(),m=rd(),k=rd(); for(i=1;i<=n;++i) a[i]=rd(),b[i]=rd(); for(i=1;i<n;++i) x=rd(),y=rd(),add(x,y),add(y,x); c=0,dfs1(1,0),dfs2(1,1),bld(1,1,n); for(i=1;i<=m;++i){ o=rd(),x=rd(),y=rd(),z=rd(); if(o==1) printf("%llu\n",qry0(x,y,z)); else mdf(1,1,n,f[x],y,z); } return 0; }