一道很无聊的题。出题人std写的是指令集暴力(
先考虑序列上怎么做,首先瞎归约一下可以发现只有根号做法。然后考虑分块,对于每个块内维护一个有序的数组,这样查询修改都是 (O(sqrt{n}log{n})) 的。然后考虑优化。首先是散块修改,可以使用归并排序做到 (O(sqrt{n}))。然后查询考虑直接维护一个指针和连续段,每次只会跳一个连续段,也可以做到 (O(sqrt{n}))。考虑上树。可以直接套用zx论文中树分块的做法,但是这样要特殊处理子树询问。
考虑树剖,直接做调整块大小是 (O(nsqrt{nlog n})) 的。然后有一个很神奇的优化(被lxl称作臭鱼烂虾分块),对每个重链分别做序列上的情况,块大小为重链长度开根。然后由于重链一定会翻倍,所以复杂度就对了。然后考虑子树查询,发现一定是一堆连续的完整重链,于是再搞个什么线段树就好了。复杂度 (O(nsqrt{n}+nlog^2{n}))。
#include<bits/stdc++.h>
#define pii std::pair<int,int>
#define mp std::make_pair
#define F first
#define S second
const int maxn=200005;
template<typename T>
inline void read(T &x){
T flag=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')flag=-1;
for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
x*=flag;
}
template<typename T>
inline void write(T x){
if(x==0)return putchar('0'),void();
int stkk[20],ttop=0;
while(x){
stkk[++ttop]=x%10;
x/=10;
}
for(int i=ttop;i>=1;i--)putchar(stkk[i]+'0');
}
template<typename T>
inline void print(T x){
if(x<0)putchar('-'),x=-x;
write(x);
putchar('
');
}
bool _;
int sum[maxn<<2];
inline void push_up(int p){
sum[p]=sum[p<<1]+sum[p<<1|1];
}
void cc(int p,int l,int r,int ppos,int v){
if(l==r)return sum[p]=v,void();
int mid=(l+r)>>1;
if(ppos<=mid)cc(p<<1,l,mid,ppos,v);
else cc(p<<1|1,mid+1,r,ppos,v);
push_up(p);
}
int qq(int p,int l,int r,int x,int y){
if(l>y||r<x)return 0;
if(x<=l&&r<=y)return sum[p];
int mid=(l+r)>>1;
return qq(p<<1,l,mid,x,y)+qq(p<<1|1,mid+1,r,x,y);
}
struct node{
int pre,to;
}edge[maxn<<1];
int head[maxn],tttot=1;
int n,m,T,lastans,fa[maxn],dep[maxn],top[maxn],dfn[maxn],pos[maxn],Dfn,sz[maxn],son[maxn],lst[maxn];
int bel[maxn],L[maxn],R[maxn],tag[maxn],pp[maxn],ss[maxn],yy[maxn],tmp[maxn],B[maxn],len[maxn],tot;;
pii w[maxn],s1[maxn],s2[maxn];
bool __;
inline void add_edge(int u,int v){
edge[++tttot]=node{head[u],v};
head[u]=tttot;
}
void dfs1(int u){
sz[u]=1;
for(int i=head[u];i;i=edge[i].pre){
int v=edge[i].to;
if(v==fa[u])continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(int u,int chain){
top[u]=chain;
dfn[pos[u]=++Dfn]=u;
if(son[u])dfs2(son[u],chain);
for(int i=head[u];i;i=edge[i].pre){
int v=edge[i].to;
if(v==son[u]||v==fa[u])continue;
dfs2(v,v);
}
lst[u]=Dfn;
if(u==chain){
for(int x=u;x;x=son[x])len[u]++;
B[u]=std::max(1,int(sqrt(len[u]*0.6)));
for(int i=pos[u],j=B[u];i<=pos[u]+len[u]-1;i++){
if(j>=B[u])
tot++,j=1,bel[i]=tot,L[tot]=i,R[tot]=i;
else
j++,bel[i]=tot,R[tot]=i;
}
}
}
inline void calc(int id){
pp[id]=R[id]+1;
for(int i=R[id];i>=L[id];i--)
if(w[i].F>0)
pp[id]=i;
for(int i=L[id],j=i;i<=R[id];i=j+1){
if(i==L[id]||w[i].F!=w[i-1].F){
for(j=i+1;j<=R[id];j++)
if(w[j].F!=w[i].F)
break;
j--;
for(int k=i;k<=j;k++)
ss[k]=i,yy[k]=j;
}
}
}
inline void build(int id){
std::sort(w+L[id],w+R[id]+1);
calc(id);
}
inline void modify(int id,int l,int r,int v){
if(v==0&&tag[id]==0)return;
int t1=0,t2=0;
for(int i=L[id];i<=R[id];i++)
w[i].F+=tag[id];
tag[id]=0;
for(int i=L[id];i<=R[id];i++){
if(l<=w[i].S&&w[i].S<=r)
w[i].F+=v,s2[++t2]=w[i];
else s1[++t1]=w[i];
}
int r1=1,r2=1;
for(int i=L[id];i<=R[id];i++)
if(r1<=t1&&r2<=t2)
w[i]=s1[r1]<s2[r2]?s1[r1++]:s2[r2++];
else if(r1<=t1)
w[i]=s1[r1++];
else if(r2<=t2)
w[i]=s2[r2++];
calc(id);
}
inline int ask(int id,int l,int r){
modify(id,-1,-1,0);
int res=0;
for(int i=L[id];i<=R[id];i++)
if(l<=w[i].S&&w[i].S<=r)
if(w[i].F>0)
res++;
return res;
}
inline int askh(int id){
return R[id]-pp[id]+1;
}
inline void change(int id,int v){
tag[id]+=v;
if(v==1){
if(pp[id]==L[id])return;
if(tag[id]+w[pp[id]-1].F>0)
pp[id]=ss[pp[id]-1];
}else if(v==-1){
if(pp[id]==R[id]+1)return;
if(tag[id]+w[pp[id]].F<=0)
pp[id]=yy[pp[id]]+1;
}
}
inline void modify_s(int l,int r,int v){
if(bel[l]==bel[r]){
modify(bel[l],l,r,v);
}else{
modify(bel[l],l,R[bel[l]],v);
modify(bel[r],L[bel[r]],r,v);
for(int i=bel[l]+1;i<bel[r];i++)
change(i,v);
}
}
inline int qry(int l,int r){
int res=0;
if(bel[l]==bel[r]){
res+=ask(bel[l],l,r);
}else{
res+=ask(bel[l],l,R[bel[l]]);
res+=ask(bel[r],L[bel[r]],r);
for(int i=bel[l]+1;i<bel[r];i++)
res+=askh(i);
}
return res;
}
int main(){
// freopen("2.in","r",stdin);
// freopen("2.out","w",stdout);
// std::cout<<(((long long)&_-(long long)&__)>>20)<<"
";
read(n);read(m);read(T);
for(int i=1,u,v;i<n;i++){
read(u);read(v);
add_edge(u,v);add_edge(v,u);
}
for(int i=1;i<=n;i++)
read(tmp[i]);
dfs1(1);dfs2(1,1);
for(int i=1;i<=n;i++)
w[i]=mp(tmp[dfn[i]],i);
for(int i=1;i<=tot;i++)build(i);
for(int i=1;i<=n;i++){
if(i==top[i]){
int ccc=qry(pos[i],pos[i]+len[i]-1);
cc(1,1,n,pos[i],ccc);
}
}
while(m--){
int op,x,y,r;
read(op);read(x);x^=lastans;
if(op==1){
read(y);read(r);
y^=lastans;
int u=x,v=y;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])std::swap(u,v);
modify_s(pos[top[u]],pos[u],r);
int ccc=qry(pos[top[u]],pos[top[u]]+len[top[u]]-1);
cc(1,1,n,pos[top[u]],ccc);
u=fa[top[u]];
}
if(dep[u]>dep[v])std::swap(u,v);
modify_s(pos[u],pos[v],r);
int ccc=qry(pos[top[u]],pos[top[u]]+len[top[u]]-1);
cc(1,1,n,pos[top[u]],ccc);
}else if(op==2){
read(y);
y^=lastans;
int u=x,v=y,ans=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])std::swap(u,v);
ans+=qry(pos[top[u]],pos[u]);
u=fa[top[u]];
}
if(dep[u]>dep[v])std::swap(u,v);
ans+=qry(pos[u],pos[v]);
print(ans);
if(T==1)lastans=ans;
}else{
int ans=qry(pos[x],pos[top[x]]+len[top[x]]-1)+qq(1,1,n,pos[top[x]]+len[top[x]],lst[x]);
print(ans);
if(T==1)lastans=ans;
}
}
return 0;
}