[四校聯考]約會
阿新 • • 發佈:2021-11-25
羊駝非常喜歡菠蘿,他們雖然身處異地(即他們不會處在同一個樹節點上),但經常到某地約會。
他們所處的世界是一棵以1為根的樹,這棵樹上的每個節點都有一個權值Wi,並且他們約會時會到他們各自所在節點的最近公共祖先(lca)上,假設他們分別處於x節點和y節點,他們的花費的代價就是Wx+Wy,有時某個節點的權值會加上某個數,有時某個節點的子樹都會加上某個數。
現在他們向你尋求幫助,他想知道當他們約會的地點為z(即lca為z時),求他們花費的期望代價。
,表示n個節點一開始的權值。
接下來m行,一共有三種操作。
“S x s”節點x的權值加上s。
“M x s”節點x的子樹(包括自己本身)每個節點都加上s。
“Q x”查詢他們約會的地點為z(即lca為z)時,求花費的期望代價。 的貢獻為\(\sum{s_i}\times{siz[f]-siz[u]}\).
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\)
接下來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\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