睡觉困难综合征 树链剖分

睡觉困难综合征

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;
}

猜你喜欢

转载自www.cnblogs.com/cj-chd/p/10155103.html