树剖,线段树维护每一位经过这个区间从左到右和从右到左0和1分别变成了啥,三个log稳T。发现其实只需要维护00000…000和1111…111会变成啥即可,这样就两个log了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<utility>
#define ull unsigned long long
#define fir first
#define sec second
#define mp make_pair
#define N 100010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<ull,int> pui;
struct edges{
int to,pre;
}e[N<<1];int top[N],d[N],h[N],etop,opt[N],in[N],tm[N];
int dfs_clock,sz[N],son[N],fa[N];ull all,x[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
inline ull gv(ull z,int p) { return z&(1ull<<p); }
struct msg{
ull v0,v1;msg(ull all=0ull) { v0=0ull,v1=all; }
inline msg& operator=(const msg &m)
{ return v0=m.v0,v1=m.v1,*this; }
inline msg& operator=(pui x)
{
if(x.sec==1) v0=0ull,v1=x.fir;//&
if(x.sec==2) v0=x.fir,v1=all;//|
if(x.sec==3) v0=x.fir,v1=all^x.fir;//^
return *this;
}
inline msg operator+(const msg &b)const
{
const msg &a=*this;msg c;
c.v0=(a.v0&b.v1)^((a.v0^all)&b.v0),
c.v1=(a.v1&b.v1)^((a.v1^all)&b.v0);
return c;
}
inline msg& operator+=(const msg &m)
{ return (*this)=(*this)+m; }
inline int show() { debug(v0)sp,debug(v1)ln;return 0; }
}lst[50];
struct segment{
int l,r;
segment *ch[2];
msg ltr,rtl;
}*rt;
int push_up(segment* &rt)
{ return rt->ltr=rt->ch[0]->ltr+rt->ch[1]->ltr,rt->rtl=rt->ch[1]->rtl+rt->ch[0]->rtl,0; }
int build(segment* &rt,int l,int r)
{
rt=new segment,rt->l=l,rt->r=r;int mid=(l+r)>>1;
if(l==r) return rt->ltr=rt->rtl=mp(x[tm[l]],opt[tm[r]]),0;//,debug(l)sp,debug(tm[l])sp,debug(x[tm[l]])sp,debug(opt[tm[r]])ln,rt->ltr.show();
return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),push_up(rt);//,debug(l)sp,debug(r)ln,rt->ltr.show(),rt->rtl.show();
}
int update(segment* &rt,int p,pui v)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(l==r) return rt->ltr=rt->rtl=v,0;
return update(rt->ch[p>mid],p,v),push_up(rt);
}
msg query_ltr(segment* &rt,int s,int t)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t) return rt->ltr;msg ans(all);
if(s<=mid) ans+=query_ltr(rt->ch[0],s,t);
if(mid<t) ans+=query_ltr(rt->ch[1],s,t);
return ans;
}
msg query_rtl(segment* &rt,int s,int t)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t) return rt->rtl;msg ans(all);
if(mid<t) ans+=query_rtl(rt->ch[1],s,t);
if(s<=mid) ans+=query_rtl(rt->ch[0],s,t);
return ans;
}
int fir_dfs(int x,int f=0)
{
d[x]=d[fa[x]=f]+1;
for(int i=h[x],y;i;i=e[i].pre)
if((y=e[i].to)^fa[x])
{
sz[x]+=fir_dfs(y,x);
if(sz[y]>sz[son[x]]) son[x]=y;
}
return ++sz[x];
}
int sec_dfs(int x)
{
tm[in[x]=++dfs_clock]=x;
if(son[x]) top[son[x]]=top[x],sec_dfs(son[x]);
for(int i=h[x],y;i;i=e[i].pre)
if((y=e[i].to)!=fa[x]&&e[i].to!=son[x])
top[y]=y,sec_dfs(y);
return 0;
}
inline int getLCA(int x,int y)
{
for(;top[x]^top[y];x=fa[top[x]])
if(d[top[x]]<d[top[y]]) swap(x,y);
return d[x]<d[y]?x:y;
}
msg query(int x,int y,msg ans=msg(all))
{
int c=getLCA(x,y),t=0;
while(d[top[x]]>=d[c]) ans+=query_rtl(rt,in[top[x]],in[x]),x=fa[top[x]];
if(d[x]>=d[c]) ans+=query_rtl(rt,in[c],in[x]);
while(d[top[y]]>d[c]) lst[++t]=query_ltr(rt,in[top[y]],in[y]),y=fa[top[y]];
if(d[y]>d[c]) lst[++t]=query_ltr(rt,in[c]+1,in[y]);
for(int i=t;i;i--) ans+=lst[i];return ans;
}
ull get_ans(int x,int y,ull z,int k,ull ans=0ull)
{
msg res=query(x,y);
for(int i=k-1,eql=1;i>=0;i--)
{
ull v0=gv(res.v0,i),v1=gv(res.v1,i);
if(eql)
if(gv(z,i))
if(v0<v1) ans|=v1;
else ans|=v0,eql=0;
else ans|=v0;
else ans|=max(v0,v1);
}
return ans;
}
int main()
{
int n,m,k;scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<k;i++) all|=(1ull<<i);
for(int i=1;i<=n;i++) scanf("%d%llu",&opt[i],&x[i]);
for(int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&x,&y);
add_edge(x,y),add_edge(y,x);
}
fir_dfs(1),top[1]=1,sec_dfs(1),build(rt,1,n);
while(m--)
{
int kd,x,y;ull z;scanf("%d%d%d%llu",&kd,&x,&y,&z);
if(kd==1) printf("%llu\n",get_ans(x,y,z,k));
else update(rt,in[x],make_pair(z,y));
}
return 0;
}