- 对于换根操作,分三种情况讨论
- 如果当前根就是要修改的点,那就直接全局修改
- 如果当前根在要修改的子树之外,那就直接修改这个子树
- 否则,通过画图可以发现,u的子树就是全树去掉(u,root)路径上深度最浅的点的子树
#include <bits/stdc++.h>
using namespace std;
vector<int>a[100005];
int dfn[100005],d[100005],s[100005],z[100005],h[100005],f[100005][17],tot,n;
int w[100005],c[100005];
void dfs1(int n1)
{
s[n1]=1;
for(int i=0;i<a[n1].size();i++)
{
d[a[n1][i]]=d[n1]+1;
f[a[n1][i]][0]=n1;
dfs1(a[n1][i]);
s[n1]+=s[a[n1][i]];
if(s[z[n1]]<s[a[n1][i]])
{
z[n1]=a[n1][i];
}
}
}
void dfs2(int n1)
{
dfn[n1]=++tot;
w[tot]=c[n1];
if(z[n1])
{
h[z[n1]]=h[n1];
dfs2(z[n1]);
}
for(int i=0;i<a[n1].size();i++)
{
if(!dfn[a[n1][i]])
{
h[a[n1][i]]=a[n1][i];
dfs2(a[n1][i]);
}
}
}
struct t1
{
int l,r;
long long v,bj;
#define len(x) t[x].r-t[x].l+1
}t[400005];
void build(int p,int l,int r)
{
t[p].l=l;
t[p].r=r;
t[p].bj=0;
if(l==r)
{
t[p].v=w[l];
return;
}
int mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].v=t[p*2].v+t[p*2+1].v;
}
void spread(int p)
{
t[p*2].bj+=t[p].bj;
t[p*2+1].bj+=t[p].bj;
t[p*2].v+=t[p].bj*(len(p*2));
t[p*2+1].v+=t[p].bj*(len(p*2+1));
t[p].bj=0;
}
void change(int p,int l,int r,int v)
{
if(l<=t[p].l&&r>=t[p].r)
{
t[p].v+=(len(p))*(long long)v;
t[p].bj+=v;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)
{
change(p*2,l,r,v);
}
if(r>mid)
{
change(p*2+1,l,r,v);
}
t[p].v=t[p*2].v+t[p*2+1].v;
}
long long ask(int p,int l,int r)
{
if(l<=t[p].l&&r>=t[p].r)
{
return t[p].v;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
long long va=0;
if(l<=mid)
{
va+=ask(p*2,l,r);
}
if(r>mid)
{
va+=ask(p*2+1,l,r);
}
return va;
}
void pre()
{
for(int j=1;j<=16;j++)
{
for(int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
}
}
}
int get(int p,int q)
{
for(int i=16;i>=0;i--)
{
if(d[f[p][i]]>d[q])
{
p=f[p][i];
}
}
return p;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>c[i];
}
for(int i=2;i<=n;i++)
{
int fa;
cin>>fa;
a[fa].push_back(i);
}
d[1]=1;
dfs1(1);
dfs2(1);
build(1,1,tot);
pre();
int m;
cin>>m;
int root=1;
for(int i=1;i<=m;i++)
{
int opt,u,v,k;
cin>>opt>>u;
long long res=0;
if(opt==1)
{
root=u;
}
else if(opt==2)
{
cin>>v>>k;
while(h[u]!=h[v])
{
if(d[h[u]]<d[h[v]])
{
swap(u,v);
}
change(1,dfn[h[u]],dfn[u],k);
u=f[h[u]][0];
}
change(1,min(dfn[u],dfn[v]),max(dfn[u],dfn[v]),k);
}
else if(opt==3)
{
cin>>k;
if(dfn[root]>dfn[u]&&dfn[root]<=dfn[u]+s[u]-1)
{
change(1,1,tot,k);
u=get(root,u);
change(1,dfn[u],dfn[u]+s[u]-1,-k);
}
else if(root==u)
{
change(1,1,tot,k);
}
else
{
change(1,dfn[u],dfn[u]+s[u]-1,k);
}
}
else if(opt==4)
{
cin>>v;
while(h[u]!=h[v])
{
if(d[h[u]]<d[h[v]])
{
swap(u,v);
}
res+=ask(1,dfn[h[u]],dfn[u]);
u=f[h[u]][0];
}
res+=ask(1,min(dfn[u],dfn[v]),max(dfn[u],dfn[v]));
cout<<res<<"\n";
}
else
{
if(dfn[root]>dfn[u]&&dfn[root]<=dfn[u]+s[u]-1)
{
u=get(root,u);
res=ask(1,1,tot)-ask(1,dfn[u],dfn[u]+s[u]-1);
}
else if(root==u)
{
res=ask(1,1,tot);
}
else
{
res=ask(1,dfn[u],dfn[u]+s[u]-1);
}
cout<<res<<"\n";
}
}
return 0;
}