#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e5+100;
int n,m,tot,cnt;
int fa[N],last[N];
int son[N],deep[N],dfn[N],num[N],top[N];//重儿子 深度 dfs序 子树规模 所在重链的顶端节点
ull sum[N*4],add[N*4],mul[N*4];
struct orz{
int v,nex;}e[N];
void init()
{
cnt=0;
tot=0;
memset(last,0,sizeof(last));
memset(son,-1,sizeof(son));
}
void Inses(int x,int y)
{
cnt++;
e[cnt].v=y;
e[cnt].nex=last[x];
last[x]=cnt;
}
void dfs1(int x,int d)
{
deep[x]=d;
num[x]=1;
for (int i=last[x];i;i=e[i].nex)
{
int v=e[i].v;
dfs1(v,d+1);
num[x]+=num[v];
if (son[x]==-1 || num[v]>num[son[x]]) son[x]=v;
}
}
void dfs2(int x,int sp)
{
top[x]=sp;
dfn[x]=++tot;
if (son[x]==-1) return ;
dfs2(son[x],sp);
for (int i=last[x];i;i=e[i].nex)
{
int v=e[i].v;
if (v!=son[x]) dfs2(v,v);
}
}
void PushUp(int s)
{
sum[s]=sum[s<<1]+sum[s<<1|1];
}
void PushDown(int s,int l,int r)
{
if (mul[s]!=1)
{
mul[s<<1]*=mul[s];
mul[s<<1|1]*=mul[s];
add[s<<1]*=mul[s];
add[s<<1|1]*=mul[s];
sum[s<<1]*=mul[s];
sum[s<<1|1]*=mul[s];
mul[s]=1;
}
if (add[s])
{
add[s<<1]+=add[s];
add[s<<1|1]+=add[s];
int mid=(l+r)>>1;
sum[s<<1]+=(ull)(mid-l+1)*add[s];
sum[s<<1|1]+=(ull)(r-mid)*add[s];
add[s]=0;
}
}
void build(int s,int l,int r)
{
sum[s]=add[s]=0;
mul[s]=1;
if (l==r) return ;
int m=(l+r)>>1;
build(s<<1,l,m); build(s<<1|1,m+1,r);
PushUp(s);
}
void update(int s,int l,int r,int L,int R,ull val,int op)
{
//printf("s=%d,l=%d,r=%d,L=%d,R=%d\n",s,l,r,L,R);
if (L<=l&&r<=R)
{
if (l!=r) PushDown(s,l,r);
if (op==1)
{
mul[s]*=val;
add[s]*=val;
sum[s]*=val;
}
else if (op==2)
{
add[s]+=val;
sum[s]+=(ull)(r-l+1)*val;
}
else
{
mul[s]*=val;
add[s]*=val;
add[s]+=val;
sum[s]=(ull)(r-l+1)*val-sum[s];
}
return;
}
PushDown(s,l,r);
int mid=(l+r)>>1;
if (L<=mid) update(s<<1,l,mid,L,R,val,op);
if (R>mid) update(s<<1|1,mid+1,r,L,R,val,op);
PushUp(s);
}
ull query(int s,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return sum[s];
PushDown(s,l,r);
int mid=(l+r)>>1;
ull ans=0;
if (L<=mid) ans+=query(s<<1,l,mid,L,R);
if (R>mid) ans+=query(s<<1|1,mid+1,r,L,R);
PushUp(s);
return ans;
}
void solve(int op,int x, int y,ull val)
{
if (op==3) val=-1;
if (op<=3)
{
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x, y);
update(1,1,n,dfn[top[x]],dfn[x],val,op);
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);
update(1,1,n,dfn[x],dfn[y],val,op);
}
else
{
ull ans=0;
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x, y);
ans+=query(1,1,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);
ans+=query(1,1,n,dfn[x],dfn[y]);
printf("%llu\n",ans);
}
}
int main()
{
while (scanf("%d",&n)!=EOF)
{
init();
for (int i=2;i<=n;i++)
{
scanf("%d",&fa[i]);
Inses(fa[i],i);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
scanf("%d",&m);
int op,u,v; ull x;
while (m--)
{
scanf("%d",&op);
if (op==1 || op==2) scanf("%d%d%llu",&u,&v,&x);
else scanf("%d%d",&u,&v);
solve(op,u,v,x);
}
}
return 0;
}