[四校联考]约会

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&&lt[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&&lt[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

posted @ 2021-11-25 15:44  Aireen_Ye  阅读(42)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.