题解已经放出来了,可以推一下上面的公式。关键这题要维护很多信息,当发生一次修改节点u,我们需要用两颗线段树分别维护u的孩子层和u的孙子层,由于是区间修改,所以需要使用bfs序才能使这些点连续。对于修改u,就直接改好了,最后麻烦的是要修改从u的父亲到根的整条链,用树剖改整条链可以吗?显然不可以。。。因为size(v)-size(w)是变化的,那么从另一个角度考虑,对于某个节点v,遍历所有孩子,对于每个孩子w,size(v)-size(w)是固定的,那么我们只要知道这个w孩子被修改增加的权值就可以了,也就是我们只需要记录x*(son2[u]+1)的累加值,那么对于修改u,我们只需要用树剖更新u到根的x*(son2[u]+1)就可以了,但是每次询问,需要遍历所有的孩子,才能知道size(v)-size(w),这样复杂度要炸,但是我们知道每个节点只有一个重儿子,如果轻儿子直接更新答案到父亲,那么每次询问只要查重儿子就可以了,于是可以沿着top往上,直接修改轻儿子对父亲的贡献。这样就可以了。。。然而这题显然可以不用树剖来维护来,直接用线段树,单点更新+区间和查询,就可以完成对u到根的更新,直接修改u,查询的时候只要查子树之和,因为只有子树才会改动查询点。。。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#define ll long long
#define Maxn 300010
#define ls id<<1,l,mid
#define rs id<<1|1,mid+1,r
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
struct edge{
int to,next;
}p[Maxn];
int tot;
int head[Maxn],w[Maxn];
void addedge(int u,int v){
p[tot].to=v;
p[tot].next=head[u];
head[u]=tot++;
}
int sz[Maxn],s[Maxn],s1[Maxn],s2[Maxn],f[Maxn],g[Maxn],son[Maxn],fa[Maxn];
int dl[Maxn],dr[Maxn];
int tim;
void dfs(int u){
dl[u]=++tim;
sz[u]=1;
s[u]=f[u]=w[u];
s1[u]=s2[u]=g[u]=son[u]=0;
for(int i=head[u];~i;i=p[i].next){
int v=p[i].to;
dfs(v);
sz[u]+=sz[v];
s[u]+=s[v];
s1[u]++;
s2[u]+=s1[v]+1;
f[u]-=sz[v]*s[v];
g[u]-=sz[v]*s1[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
f[u]+=sz[u]*s[u];
g[u]+=2+sz[u]*s2[u];
dr[u]=tim;
}
int top[Maxn];
void dfs1(int u,int pre){
top[u]=pre;
if(son[u]) dfs1(son[u],pre);
for(int i=head[u];~i;i=p[i].next){
int v=p[i].to;
if(v!=son[u]) dfs1(v,v);
}
}
int e,n;
int q[Maxn],dfn[Maxn],bl[Maxn],br[Maxn],bL[Maxn],bR[Maxn];
void bfs(int u){
q[e=1]=u;
for(int i=1;i<=e;i++){
int v=q[i];
dfn[v]=i;
bl[v]=e+1;
for(int j=head[v];~j;j=p[j].next)
q[++e]=p[j].to;
br[v]=e;
if(bl[v]>br[v]) bl[v]=n+1,br[v]=0;
}
for(int i=1;i<=e;i++){
int v=q[i];
bL[v]=n+1,bR[v]=0;
for(int j=head[v];~j;j=p[j].next){
bL[v]=min(bL[v],bl[p[j].to]);
bR[v]=max(bR[v],br[p[j].to]);
}
}
}
int tr[Maxn<<2][3];
void pushup(int id){
tr[id][2]=tr[id<<1][2]+tr[id<<1|1][2];
}
void build(int id,int l,int r){
tr[id][0]=tr[id][1]=tr[id][2]=0;
if(l==r) return;
int mid=l+r>>1;
build(ls);
build(rs);
}
void update(int id,int l,int r,int a,int b,int c,int d){
if(a<=l&&r<=b){
tr[id][d]+=c;
return;
}
int mid=l+r>>1;
if(a<=mid) update(ls,a,b,c,d);
if(b>mid) update(rs,a,b,c,d);
}
void modify(int id,int l,int r,int a,int b){
if(l==r){
tr[id][2]+=b;
return;
}
int mid=l+r>>1;
if(a<=mid) modify(ls,a,b);
else modify(rs,a,b);
pushup(id);
}
int d0,d1,d2;
void query(int id,int l,int r,int a){
d0+=tr[id][0];
d1+=tr[id][1];
if(l==r) return;
int mid=l+r>>1;
if(a<=mid) query(ls,a);
else query(rs,a);
}
int query(int id,int l,int r,int a,int b){
if(a<=l&&r<=b) return tr[id][2];
int mid=l+r>>1;
int ans=0;
if(a<=mid) ans+=query(ls,a,b);
if(b>mid) ans+=query(rs,a,b);
return ans;
}
int main()
{
int Q,u,x,op;
while(~scanf("%d%d",&n,&Q)){
tot=0;
memset(head,-1,sizeof head);
for(int i=2;i<=n;i++){
fa[i]=read();
addedge(fa[i],i);
}
for(int i=1;i<=n;i++) w[i]=read();
tim=0;
dfs(1);
bfs(1);
dfs1(1,1);
build(1,1,n);
while(Q--){
op=read();
if(op==1){
u=read(),x=read();
if(bL[u]!=n+1) update(1,1,n,bL[u],bR[u],x,0);
if(bl[u]!=n+1) update(1,1,n,bl[u],br[u],x,1);
f[u]+=x*g[u];
x*=s2[u]+1;
modify(1,1,n,dl[u],x);
while(top[u]!=1){
u=top[u];
f[fa[u]]+=x*(sz[fa[u]]-sz[u]);
u=fa[u];
}
}
else{
u=read();
d0=d1=d2=0;
query(1,1,n,dfn[u]);
if(son[u]) d2=query(1,1,n,dl[son[u]],dr[son[u]]);
unsigned ans=f[u]+d0*(sz[u]+1)+d1*(2+sz[u]*s1[u])+d2*(sz[u]-sz[son[u]]);
printf("%u\n",ans);
}
}
}
return 0;
}