Description:
给定一个n个点的树,每个点有一个操作符号 "&" "|" "^" ,以及一个权值
要求支持以下操作:
1.修改x点的操作符号和权值
2.给定w,你需要找一个数v,经过从x到y的路径上的所有运算后使答案最大,输出这个答案
Hint:
\(n \le 10^5\)
Solution:
这题是 https://www.cnblogs.com/list1/p/10499412.html 的树上多组询问带修版
原题需要维护每个位最初是0/1经运算后得到的是0还是1
所以我们这题也这么做
考虑如何在线段树上合并信息
\(f_{l0} ,f_{r0} \) 表示以0进入该节点区间,经运算后得到的值
分类讨论:
当 \(f_{l0}==1 \&\& f_{r1}==0\) 或 \(f_{l1}==0 \&\& f_{r0}==0\) 时
\(f_{p0}=0\)
同理我们可以推出其他四种转移,详见代码
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef unsigned long long ll;
const int mxn=2e5+5;
const ll lim=-1;
int n,q,k,t1,t2,cnt,tot;
int o[mxn],f[mxn],sz[mxn],hd[mxn],rk[mxn],top[mxn],dep[mxn],dfn[mxn],son[mxn];
ll a[mxn];
inline ll read() {
char c=getchar(); ll x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline int chkmax(int &x,int y) {if(x<y) x=y;}
inline int chkmin(int &x,int y) {if(x>y) x=y;}
struct data {
ll f0,f1,inv0,inv1;
data() {f0=f1=inv0=inv1=0;}
}tr[mxn<<2],r1[mxn],r2[mxn];
struct ed {
int to,nxt;
}t[mxn<<1];
inline void add(int u,int v) {
t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}
void dfs1(int u,int fa)
{
dep[u]=dep[fa]+1; sz[u]=1; f[u]=fa;
for(int i=hd[u];i;i=t[i].nxt) {
int v=t[i].to;
if(v==fa) continue ;
dfs1(v,u); sz[u]+=sz[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
}
void dfs2(int u,int tp)
{
dfn[u]=++tot; rk[tot]=u; top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=hd[u];i;i=t[i].nxt) {
int v=t[i].to;
if(v==f[u]||v==son[u]) continue ;
dfs2(v,v);
}
}
ll cal(ll val,int x)
{
if(o[x]==1) return val&a[x];
if(o[x]==2) return val|a[x];
if(o[x]==3) return val^a[x];
}
data push_up(data lc,data rc)
{
data res;
res.f0=((lc.f0&rc.f1)|((~lc.f0)&rc.f0));
res.f1=((lc.f1&rc.f1)|((~lc.f1)&rc.f0));
res.inv0=((rc.inv0&lc.inv1)|((~rc.inv0)&lc.inv0));
res.inv1=((rc.inv1&lc.inv1)|((~rc.inv1)&lc.inv0));
return res;
}
void build(int l,int r,int p)
{
if(l==r) {
tr[p].f0=tr[p].inv0=cal(0,rk[l]);
tr[p].f1=tr[p].inv1=cal(lim,rk[l]);
return ;
}
int mid=(l+r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
tr[p]=push_up(tr[ls],tr[rs]);
}
void update(int l,int r,int pos,int p)
{
if(l==r) {
tr[p].f0=tr[p].inv0=cal(0,rk[l]);
tr[p].f1=tr[p].inv1=cal(lim,rk[l]);
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) update(l,mid,pos,ls);
else update(mid+1,r,pos,rs);
tr[p]=push_up(tr[ls],tr[rs]);
}
data query(int l,int r,int ql,int qr,int p)
{
if(ql<=l&&r<=qr) return tr[p]; int mid=(l+r)>>1;
if(qr<=mid) return query(l,mid,ql,qr,ls);
else if(ql>mid) return query(mid+1,r,ql,qr,rs);
else return push_up(query(l,mid,ql,qr,ls),query(mid+1,r,ql,qr,rs));
}
data solve(int x,int y)
{
t1=t2=0;
while(top[x]!=top[y]) {
if(dep[top[x]]>=dep[top[y]]) {
r1[++t1]=query(1,n,dfn[top[x]],dfn[x],1);
x=f[top[x]];
}
else {
r2[++t2]=query(1,n,dfn[top[y]],dfn[y],1);
y=f[top[y]];
}
}
if(dep[x]>dep[y]) r1[++t1]=query(1,n,dfn[y],dfn[x],1);
else r2[++t2]=query(1,n,dfn[x],dfn[y],1);
data res;
for(int i=1;i<=t1;++i)
swap(r1[i].f0,r1[i].inv0),swap(r1[i].f1,r1[i].inv1);
if(t1) {
res=r1[1];
for(int i=2;i<=t1;++i) res=push_up(res,r1[i]);
if(t2) res=push_up(res,r2[t2]);
}
else res=r2[t2];
for(int i=t2-1;i>=1;--i) res=push_up(res,r2[i]);
return res;
}
int main()
{
n=read(); q=read(); k=read(); int opt,u,v; ll w,ans;
for(int i=1;i<=n;++i) o[i]=read(),a[i]=read();
for(int i=1;i<n;++i) {
u=read(); v=read();
add(u,v); add(v,u);
}
dfs1(1,0); dfs2(1,1); build(1,n,1);
for(int i=1;i<=q;++i) {
opt=read(); u=read(); v=read(); w=read();
if(opt==2) {
o[u]=v; a[u]=w;
update(1,n,dfn[u],1);
}
else {
data res=solve(u,v); ans=0; ll tp0,tp1;
for(int i=63;i>=0;--i)
if(res.f0>>i&1ull) ans|=1ull<<i;
else if((res.f1>>i&1)&&(1ull<<i)<=w) ans|=1ull<<i,w-=1ull<<i;
printf("%llu\n",ans);
}
}
return 0;
}