Problem
Solution
第一想法是链剖+线段树好像可以做,只不过细节有点多。不过好像还可以cdq分治,但是cdq写起来还是不爽,得树剖+线段树,时间复杂度也并不优秀 O ( m log m log n 2 ) O(m\log m\log n^2) O(mlogmlogn2)。我们考虑用线段树合并的方法来实现。
由于每次操作都是从某点加到根,那么这个操作用线段树合并很好搞。考虑把线段树的的区间搞成时间,那么对于2操作,我们其实就只需要统计一下之前的1操作的影响即可加入答案,这个在时间线段树上很好做,即每次向右子树走时加入左子树的贡献。当我们合并子树的线段树时,考虑一下子树之间会做什么贡献,有点类似POI的rot,而这个是差分的贡献,所以还要把儿子的答案累加一下。
时间复杂度 O ( m log n ) O(m\log n) O(mlogn)。
Code
#include <algorithm>
#include <cstdio>
#define rg register
#define pushup(rt) a[rt]=a[lc[rt]]+a[rc[rt]],b[rt]=b[lc[rt]]+b[rc[rt]]
using namespace std;
typedef long long ll;
const int maxn=100010,maxm=2000010;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
struct data{int v,nxt;}edge[maxn];
int n,m,p,sz,head[maxn],rt[maxn],lc[maxm],rc[maxm];
ll res,ans[maxn],a[maxm],b[maxm];
inline void insert(int u,int v){edge[++p]=(data){v,head[u]};head[u]=p;}
void update(int l,int r,int pos,ll va,ll vb,int &rt)
{
if(!rt) rt=++sz;
if(l==r){a[rt]+=va;b[rt]+=vb;return ;}
int m=(l+r)>>1;
if(pos<=m) update(l,m,pos,va,vb,lc[rt]);
else{res+=a[lc[rt]]*vb;update(m+1,r,pos,va,vb,rc[rt]);}
pushup(rt);
}
void input()
{
int op,x,d;
read(n);
for(rg int i=2;i<=n;i++){read(x);insert(x,i);}
read(m);
for(rg int i=1;i<=m;i++)
{
read(op);read(x);read(d);res=0;
if(op==1) update(1,m,i,d,0,rt[x]);
if(op==2) update(1,m,i,0,d,rt[x]);
ans[x]+=res;
}
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
res+=a[lc[x]]*b[rc[y]];
res+=a[lc[y]]*b[rc[x]];
lc[x]=merge(lc[x],lc[y]);
rc[x]=merge(rc[x],rc[y]);
pushup(x);
return x;
}
void dfs(int x)
{
for(int i=head[x];i;i=edge[i].nxt)
{
dfs(edge[i].v);res=0ll;
rt[x]=merge(rt[x],rt[edge[i].v]);
ans[x]+=res+ans[edge[i].v];
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
input();
dfs(1);
for(rg int i=1;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}