睡觉困难综合征 树链剖分
睡觉困难综合征
树剖好题。
做这道题之前,请先做一做[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\),那么\(k[0][0]\)就是\((p[0][0]\&q[0][1])|((\)$p[0][0])&q[0][0])$。这个结论请自己手玩~证明,对于其他信息的合并也可以使用同样的方式推导。
在修改时,直接在线段树上更改某个点的值就好了。对于每一个询问,可以使用上面合并区间的方法合并重链上的信息,合并时注意谁是左区间谁右区间,从线段树上得到信息之后就按照区间上的做法一遍贪心得到答案。
注意必须使用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;
}