Gardener Bo
Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 182 Accepted Submission(s): 67
Problem Description
Gardener Bo loves Trees.Now he asks you to help him take care of his lovely tree.
A rooted tree with root=1 is given.Every node on the tree has a value wi .Let fa[u] be the father of u .
Let LCA(u,v) be the least common ancestor of u and v .The expression [condition] is 1 when condition is True,is 0 when condition is False.
Define
Now there are Q events happening.Each event has one of two types:
1 u x :pick out all v that satisfies v=u or fa[v]=u or fa[fa[v]]=u ,and add x to wv .
2 u :query f(u)mod232 .
A rooted tree with root=1 is given.Every node on the tree has a value wi .Let fa[u] be the father of u .
Let LCA(u,v) be the least common ancestor of u and v .The expression [condition] is 1 when condition is True,is 0 when condition is False.
Define
f(u)=∑i=1n∑j=in(wi+wj)∗[LCA(i,j)=u]
Now there are Q events happening.Each event has one of two types:
1 u x :pick out all v that satisfies v=u or fa[v]=u or fa[fa[v]]=u ,and add x to wv .
2 u :query f(u)mod232 .
Input
There are several test cases.
The first line contains two integers n,Q .
The second line contains n−1 integers,i-th indicates fa[i+1] .
The third line contains n integers,the i-th indicates the initial wi .
Following Q lines each describes an event.
1≤n,Q≤3×105,|wi|,|x|<109
The first line contains two integers n,Q .
The second line contains n−1 integers,i-th indicates fa[i+1] .
The third line contains n integers,the i-th indicates the initial wi .
Following Q lines each describes an event.
1≤n,Q≤3×105,|wi|,|x|<109
Output
For every event with type 2,you should print a number indicating the answer.
Sample Input
5 3 1 1 3 3 -5 2 0 7 -6 1 5 2 2 3 2 2 10 5 1 2 3 3 1 2 6 2 2 -2 5 8 -6 0 -4 6 6 8 9 2 10 1 3 4 1 6 -2 2 9 2 4
题意:一棵树有n个节点,以1为根节点,每个节点有权值wi,定义f(u)为以u为根的子树中,LCA(u,v)=u的所有点对的权值和
有2种操作:
①选择点u,将u点以及它的子节点和孙子节点的权值都加上x
②查询f(u)
题解:具体的公式上面也给出了,最好对照的推一下公式。
其实对于1,2,3部分没必要用线段树维护,考虑到除了x都是常量,因此每次更新的时候只要打上标记:add[u]+=x,查询的时候加来就行。
对于第4部分,用树链剖分维护即可。每次更新点u,对于它的祖先中轻链上的点直接单点更新(轻链上的点的个数不超过logN个),然后由于一个节点只有1条重链,只要用树剖+线段树维护每个点对重链上的点的贡献即可。
#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
typedef unsigned int UI;
const int MX = 3e5 + 5;
const int inf = 0x3f3f3f3f;
struct Edge{
int v,nxt;
}E[MX*2];
int head[MX],tot;
int n,m;
int fa[MX],son[MX],top[MX];
int dfn[MX],out[MX],dfp;
UI f[MX],c[MX],w[MX];
UI sz[MX],cnt_son1[MX],cnt_son2[MX];
UI add[MX],sum[MX<<2];
void init(){
memset(add,0,sizeof(add));
memset(sum,0,sizeof(sum));
memset(head,-1,sizeof(head));
tot=dfp=0;
}
void add_edge(int u,int v){
E[tot].v=v;
E[tot].nxt=head[u];
head[u]=tot++;
}
void dfs1(int u){
cnt_son1[u]=cnt_son2[u]=son[u]=c[u]=0;
sz[u]=1;
for(int i=head[u];~i;i=E[i].nxt){
int v=E[i].v;
if(v==fa[u]) continue;
dfs1(v);
sz[u]+=sz[v];
cnt_son1[u]++;
cnt_son2[u]+=cnt_son1[v]+1;
c[u]+=sz[v]*cnt_son1[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
f[u]=w[u]*(sz[u]+1);
for(int i=head[u];~i;i=E[i].nxt){
int v=E[i].v;
if(v==fa[u]) continue;
f[u]+=(sz[u]-sz[v])*w[v];
w[u]+=w[v];
}
}
void dfs2(int u,int t){
top[u]=t;
dfn[u]=++dfp;
if(son[u]) dfs2(son[u],t);
for(int i=head[u];~i;i=E[i].nxt){
int v=E[i].v;
if(v==son[u]||v==fa[u]) continue;
dfs2(v,v);
}
out[u]=dfp;
}
void update(int x,UI val){
while(top[x]!=top[1]){
int v=top[x],u=fa[v];
f[u]+=(sz[u]-sz[v])*val;
x=u;
}
}
void Update(int p,UI val,int l,int r,int rt){
sum[rt]+=val;
if(l==r) return;
int m=(l+r)>>1;
if(p<=m) Update(p,val,lson);
else Update(p,val,rson);
}
UI query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r) return sum[rt];
int m=(l+r)>>1;
UI ret=0;
if(L<=m) ret+=query(L,R,lson);
if(R>m) ret+=query(L,R,rson);
return ret;
}
void solve(){
init();
for(int i=2;i<=n;i++) {
scanf("%d",&fa[i]);
add_edge(fa[i],i);add_edge(i,fa[i]);
}
for(int i=1;i<=n;i++) scanf("%u",&w[i]);
dfs1(1);
dfs2(1,1);
while(m--){
int op,u;
UI x;
scanf("%d",&op);
if(op==1){
scanf("%d%u",&u,&x);
add[u]+=x;
update(u,x*(1+cnt_son2[u]));
Update(dfn[u],x*(1+cnt_son2[u]),1,n,1);
}
else{
scanf("%d",&u);
UI ans=f[u];
ans+=add[u]*(2+sz[u]*cnt_son2[u]-c[u]);
if(fa[u]) ans+=add[fa[u]]*(2+sz[u]*cnt_son1[u]);
if(fa[fa[u]]) ans+=add[fa[fa[u]]]*(1+sz[u]);
if(son[u]) { //son[u]存在表示u是重链上的
ans+=(sz[u]-sz[son[u]])*query(dfn[son[u]],out[son[u]],1,n,1);
}
printf("%u\n",ans);
}
}
}
int main(){
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m)) solve();
return 0;
}