1. 程式人生 > >睡覺困難綜合徵 樹鏈剖分

睡覺困難綜合徵 樹鏈剖分

睡覺困難綜合徵

LG傳送門

樹剖好題。

做這道題之前,請先做一做[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;
}