前置技能:[Noi2014]起床困难综合症。
不难看出,这道题其实就是上一道题的加强版
在上一道题中,因为位运算时位与位之间互不干扰
所以从高位到低位枚举初始值二进制上的每一位为0和为1时,经过n次计算后这一位的结果,贪心选取
在这题中,我们也可以用同样的思路求取答案
因为有树上路径查询,考虑树链剖分,用线段树维护每一位初始为0和1时,经过一个区间的计算变为多少
因为&、|、^ 运算都符合结合律,所以这样做是可行的
问题是,&、|、^ 运算并不都满足交换律,即每个区间从左到右计算和从右到左计算得到的结果是不同的
而在树上从x走到y的途中,并不保证一定按dfn序从小到大的顺序走
所以我们还要分别维护每个区间从左到右计算和从右到左计算的结果
另外,给每一位都开一颗线段树显然是不现实的,
考虑到 k<=64,我们使用状压,把所有位都压到一起,存到一颗线段树中(注意要开unsigned long long)
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=100010;
ull read(){
ull x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct Edge{
int u,v,nxt;
}edge[N<<1];
int head[N],cnt;
void addedge(int u,int v){
edge[++cnt]=(Edge){u,v,head[u]};head[u]=cnt;
edge[++cnt]=(Edge){v,u,head[v]};head[v]=cnt;
}
int n,m,k;
int dep[N],son[N],sz[N],top[N],fa[N],tid[N],rnk[N],ind;
void dfs1(int u,int f){
fa[u]=f;
dep[u]=dep[f]+1;
sz[u]=1;
for(int i=head[u];~i;i=edge[i].nxt)
if(edge[i].v!=f){
dfs1(edge[i].v,u);
if(sz[edge[i].v]>sz[son[u]]) son[u]=edge[i].v;
sz[u]+=sz[edge[i].v];
}
}
void dfs2(int u,int tp){
top[u]=tp;
tid[u]=++ind;
rnk[ind]=u;
if(sz[u]>1) dfs2(son[u],tp);
for(int i=head[u];~i;i=edge[i].nxt)
if(edge[i].v!=son[u]&&edge[i].v!=fa[u])
dfs2(edge[i].v,edge[i].v);
}
ull tran[N<<3][2][2];
//tran[o][0:带进0计算 ? 1:带进1计算][0:从左往右算 ? 1:从右往左算]
inline ull transf(ull a,ull b,int opt){
if(opt==1){
return a&b;
}else if(opt==2){
return a|b;
}else return a^b;
}
int op;
inline ull transf(ull a,ull b){
if(op==1){
return a&b;
}else if(op==2){
return a|b;
}else return a^b;
}
inline void pushup(int o){
int ls=o<<1,rs=o<<1|1;
tran[o][1][0]=(tran[ls][1][0]&tran[rs][1][0])|(~tran[ls][1][0]&tran[rs][0][0]);
tran[o][1][1]=(tran[rs][1][1]&tran[ls][1][1])|(~tran[rs][1][1]&tran[ls][0][1]);
tran[o][0][0]=(tran[ls][0][0]&tran[rs][1][0])|(~tran[ls][0][0]&tran[rs][0][0]);
tran[o][0][1]=(tran[rs][0][1]&tran[ls][1][1])|(~tran[rs][0][1]&tran[ls][0][1]);
}
void update(int o,int l,int r,int x,ull k){
if(l==r){
tran[o][0][0]=tran[o][0][1]=transf(0ull,k);
tran[o][1][0]=tran[o][1][1]=transf(~0ull,k);
}
else{
int mid=l+r>>1;
if(x<=mid) update(o<<1,l,mid,x,k);
else update(o<<1|1,mid+1,r,x,k);
pushup(o);
}
}
ull t1[2],t0[2];
int t;
void query(int o,int l,int r,int a,int b){
if(a<=l&&b>=r){
if(!t){
ull tt=t1[t];
t1[t]=(tran[o][1][t]&t1[t])|(~tran[o][1][t]&t0[t]);
t0[t]=(tran[o][0][t]&tt)|(~tran[o][0][t]&t0[t]);
}else{
t1[t]=(t1[t]&tran[o][1][t])|(~t1[t]&tran[o][0][t]);
t0[t]=(t0[t]&tran[o][1][t])|(~t0[t]&tran[o][0][t]);
}
}
else{
int mid=l+r>>1;
if(b>mid) query(o<<1|1,mid+1,r,a,b);
if(a<=mid) query(o<<1,l,mid,a,b);
}
}
ull val[N];
int opt[N];
void build(int o,int l,int r){
if(l==r){
tran[o][0][0]=tran[o][0][1]=transf(0ull,val[rnk[l]],opt[rnk[l]]);
tran[o][1][0]=tran[o][1][1]=transf(~0ull,val[rnk[l]],opt[rnk[l]]);
}
else{
int mid=l+r>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);
}
}
ull z;
inline ull ask(int x,int y){
t0[0]=t0[1]=0;
t1[0]=t1[1]=~0ull;
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]]){
t=1;
query(1,1,n,tid[top[x]],tid[x]);
x=fa[top[x]];
}
else{
t=0;
query(1,1,n,tid[top[y]],tid[y]);
y=fa[top[y]];
}
}
if(dep[x]>dep[y]){
t=1;
query(1,1,n,tid[y],tid[x]);
}
else{
t=0;
query(1,1,n,tid[x],tid[y]);
}
ull T0=(t0[1]&t1[0])|(~t0[1]&t0[0]);
ull T1=(t1[1]&t1[0])|(~t1[1]&t0[0]);
ull v=0,ans=0;
for(int i=k;~i;i--){
ull v1=v|(1ull<<i);
if(v1<=z){
if(T0&(1ull<<i)||!(T1&(1ull<<i)))
ans|=T0&(1ull<<i);
else{
ans|=T1&(1ull<<i);
v|=(1ull<<i);
}
}
else{
ans|=T0&(1ull<<i);
}
}
return ans;
}
int main(){
memset(head,cnt=-1,sizeof(head));
n=read();m=read();k=read();k--;
for(int i=1;i<=n;i++)
opt[i]=read(),val[i]=read();
for(int i=1;i<n;i++)
addedge(read(),read());
dfs1(1,1);
dfs2(1,1);
build(1,1,n);
while(m--){
int q=read(),x=read( ),y=read( );z=read( );
if(q==1)
printf("%llu\n",ask(x,y));
else{
op=y;
update(1,1,n,tid[x],z);
}
}
return 0;
}