[四校联考]约会
Description
羊驼非常喜欢菠萝,他们虽然身处异地(即他们不会处在同一个树节点上),但经常到某地约会。 他们所处的世界是一棵以1为根的树,这棵树上的每个节点都有一个权值Wi,并且他们约会时会到他们各自所在节点的最近公共祖先(lca)上,假设他们分别处于x节点和y节点,他们的花费的代价就是\(W_x+W_y\),有时某个节点的权值会改加上某个数,有时某个节点的子树都会加上某个数。 现在他们向你寻求帮助,他想知道当他们约会的地点为z(即lca为z时),求他们花费的期望代价。
Input
第一行输入一个整数n,m,n是节点个数,m是操作总数。
第二行读入n-1个整数\(f_i\),表示2-n节点的父亲。
第三行读入n个整数\(s_i\),表示n个节点一开始的权值。
接下来m行,一共有三种操作。
“S x s”节点x的权值加上s。
“M x s”节点x的子树(包括自己本身)每个节点都加上s。
“Q x”查询他们约会的地点为z(即lca为z)时,求花费的期望代价。
Output
对于每一个Q输出一个实数ans,绝对误差在\(10^{-4}\)以内就视为正确。
Sample Input
5 4
1 1 1 1
1 2 2 3 3
Q 1
S 1 4
M 1 -2
Q 1
Sample Output
4.400000
2.000000
HINT
\(n,m\leq300000,-10^5\leq{s}\leq10^5\).
Solution
以 \(u\) 为根的子树对父亲 \(f\) 的贡献为\(\sum{s_i}\times{siz[f]-siz[u]}\).
对树进行轻重链剖分,对于每个询问,\(\sum\varDelta{s_i}\)是固定的.
除了\(x\)之外,其他改变的贡献均为\(\sum\varDelta{s_i}\times{siz[f]-siz[u]}\)
对于轻链直接暴力修改,重链线段树维护 \(siz[f]-siz[son[f]]\) 及相关值即可.
#define N 300005
#define M 3000005
typedef long long ll;
struct graph{
int nxt,to;
}e[N];
ll s[N],tot[N],ans[N];
int dep[N],siz[N],son[N],top[N];
int g[N],f[N],w[N],p[N],n,m,cnt;
inline void addedge(int x,int y){
e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
}
inline void dfs1(int u){
int mx=0;siz[u]=1;
for(int i=g[u],c;i;i=e[i].nxt){
f[c=e[i].to]=u;
dep[c]=dep[u]+1;dfs1(c);
siz[u]+=siz[c];
if(siz[c]>mx){
mx=siz[c];son[u]=c;
}
}
}
inline void dfs2(int u,int tp){
int c;
tot[u]=1ll*(siz[u]-1);
ans[u]=1ll*s[u]*(siz[u]-1);
p[u]=++cnt;w[cnt]=u;top[u]=tp;
if(c=son[u]){
dfs2(son[u],tp);
s[u]+=s[c];
ans[u]+=1ll*s[c]*(siz[u]-siz[c]);
tot[u]+=1ll*(siz[u]-siz[c])*siz[c];
}
for(int i=g[u];i;i=e[i].nxt)
if((c=e[i].to)!=son[u]) {
dfs2(c,c);
s[u]+=s[c];
ans[u]+=1ll*s[c]*(siz[u]-siz[c]);
tot[u]+=1ll*(siz[u]-siz[c])*siz[c];
}
tot[u]>>=1;
}
struct SegMent{
int l,r;ll sum/*ans*/,lzy/**/,lzt/*tot[u]<<1*/;
}lt[M];
inline void build(int u,int l,int r){
lt[u].l=l;lt[u].r=r;
if(lt[u].l<lt[u].r){
int lef=u<<1,rig=u<<1|1;
int mid=(lt[u].l+lt[u].r)>>1;
build(lef,l,mid);build(rig,mid+1,r);
}
else{
int p=w[lt[u].l];
lt[u].sum=ans[p];
}
}
inline void pushdown(int u){
if(!lt[u].lzy&&!lt[u].lzt) return;
if(lt[u].l<lt[u].r){
int lef=u<<1,rig=u<<1|1;ll s;
s=lt[u].lzy;lt[lef].lzy+=s;lt[rig].lzy+=s;
s=lt[u].lzt;lt[lef].lzt+=s;lt[rig].lzt+=s;
}
else{
ll s=lt[u].lzy;int p=w[lt[u].l];
lt[u].sum+=1ll*(siz[p]-siz[son[p]])*s;
s=lt[u].lzt;lt[u].sum+=1ll*(tot[p]<<1ll)*s;
}
lt[u].lzy=lt[u].lzt=0;
}
inline void add_s(int u,int l,int r,ll s){
if(lt[u].l>=l&<[u].r<=r){
lt[u].lzy+=s;return;
}
if(lt[u].l<lt[u].r){
int lef=u<<1,rig=u<<1|1;
int mid=(lt[u].l+lt[u].r)>>1;
if(l<=mid) add_s(lef,l,r,s);
if(r>mid) add_s(rig,l,r,s);
}
}
inline void add_t(int u,int l,int r,ll s){
if(lt[u].l>=l&<[u].r<=r){
lt[u].lzt+=s;return;
}
if(lt[u].l<lt[u].r){
int lef=u<<1,rig=u<<1|1;
int mid=(lt[u].l+lt[u].r)>>1;
if(l<=mid) add_t(lef,l,r,s);
if(r>mid) add_t(rig,l,r,s);
}
}
inline void add(int u,int x,ll s){
pushdown(u);
if(lt[u].l==lt[u].r){
lt[u].sum+=s;return;
}
if(lt[u].l<lt[u].r){
int lef=u<<1,rig=u<<1|1;
int mid=(lt[u].l+lt[u].r)>>1;
if(x<=mid) add(lef,x,s);
else add(rig,x,s);
}
}
inline ll ask(int u,int x){
pushdown(u);
if(lt[u].l==lt[u].r)
return lt[u].sum;
if(lt[u].l<lt[u].r){
int lef=u<<1,rig=u<<1|1;
int mid=(lt[u].l+lt[u].r)>>1;
if(x<=mid) return ask(lef,x);
return ask(rig,x);
}
}
inline void change(int u,int lst,ll s){
if(!u) return;
if(lst==top[lst]){
add(1,p[u],1ll*s*(siz[u]-siz[lst]));
if(p[top[u]]<p[u])
add_s(1,p[top[u]],p[u]-1,s);
}
else add_s(1,p[top[u]],p[u],s);
lst=top[u];u=f[top[u]];
while(u){
add(1,p[u],1ll*s*(siz[u]-siz[lst]));
if(p[top[u]]<p[u])
add_s(1,p[top[u]],p[u]-1,s);
lst=top[u];u=f[top[u]];
}
}
inline void Aireen(){
n=read();m=read();
for(int i=2;i<=n;++i) addedge(read(),i);
for(int i=1;i<=n;++i) s[i]=1ll*read();
dep[1]=1;dfs1(1);
cnt=0;dfs2(1,1);build(1,1,n);
char c[2];int x,s;
while(m--){
scanf("%s",&c);x=read();
if(c[0]=='S') s=read(),add(1,p[x],1ll*(siz[x]-1)*s),change(f[x],x,1ll*s);
else if(c[0]=='M') s=read(),add_t(1,p[x],p[x]+siz[x]-1,s),change(f[x],x,1ll*s*siz[x]);
else printf("%lf\n",(double)(ask(1,p[x]))/(double)(tot[x]));
}
}
2017-04-20 19:53:21