題目描述:
題目分析:
首先把答案分爲兩部分,一部分是LCA在虛兒子內部的,記爲 xans,一部分是LCA在prefer鏈上的,合計爲ans
貢獻在splay樹上分步統計,實際上存的都是受x在splay中的子樹中的節點管轄的貢獻
在計算ans之前,先更新:
剩下的就是在的時候更新虛兒子對的貢獻。
注意此題因爲樹的形態是確定的,所以的時候不能換根,的時候將 之後它的左兒子不一定是它樹上的父親,但是斷掉這條邊仍然等價於cut,注意是令而不是令。
Code:
#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,m,a[maxn],F[maxn];
namespace LCT{
int fa[maxn],ch[maxn][2],siz[maxn],xsz[maxn];
long long all[maxn],ans[maxn],sz2[maxn],xans[maxn];
#define pa fa[x]
bool isr(int x){return ch[pa][0]!=x&&ch[pa][1]!=x;}
bool isc(int x){return ch[pa][1]==x;}
void upd(int x){
siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + xsz[x];
all[x] = all[ch[x][0]] + all[ch[x][1]] + 1ll*a[x]*xsz[x];
ans[x] = ans[ch[x][0]] + ans[ch[x][1]] + xans[x]
+ a[x]*(1ll*xsz[x]*xsz[x]-sz2[x] + 2ll*xsz[x]*siz[ch[x][1]]) + 2ll*all[ch[x][0]]*(siz[x]-siz[ch[x][0]]);
}
void rot(int x){
int y=fa[x],z=fa[y],c=isc(x);
!isr(y)&&(ch[z][isc(y)]=x);
fa[ch[y][c]=ch[x][!c]]=y,fa[ch[x][!c]=y]=x,fa[x]=z;
upd(y);
}
void splay(int x){
for(;!isr(x);rot(x)) if(!isr(pa)) rot(isc(pa)==isc(x)?pa:x); upd(x);
}
void access(int x){
for(int y=0;x;x=fa[y=x]){
splay(x);
xsz[x]+=siz[ch[x][1]]-siz[y];
sz2[x]+=1ll*siz[ch[x][1]]*siz[ch[x][1]]-1ll*siz[y]*siz[y];
xans[x]+=ans[ch[x][1]]-ans[y];
ch[x][1]=y,upd(x);
}
}
void prefer(int x){access(x),splay(x);}
void link(int x,int y){
splay(x),prefer(y);
fa[x]=y,xsz[y]+=siz[x],sz2[y]+=1ll*siz[x]*siz[x],xans[y]+=ans[x],upd(y);
}
void cut(int x){prefer(x),ch[x][0]=fa[ch[x][0]]=0,upd(x);}
}
using namespace LCT;
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++) scanf("%d",&F[i]);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),xsz[i]=1;
for(int i=2;i<=n;i++) link(i,F[i]);
splay(1),printf("%.9f\n",1.*ans[1]/n/n);
scanf("%d",&m); char op[2];
for(int i=1,x,y;i<=m;i++){
scanf("%s%d%d",op,&x,&y);
if(op[0]=='P'){
if(prefer(y),splay(x),!isr(y)) swap(x,y);//awesome!
cut(x),link(x,F[x]=y);
printf("%.9f\n",1.*ans[y]/n/n);
}
else prefer(x),a[x]=y,upd(x),printf("%.9f\n",1.*ans[x]/n/n);
}
}
/*首先把答案分爲兩部分,一部分是LCA在虛兒子內部的,記爲 xans,一部分是LCA在prefer鏈上的,合計爲ans
貢獻在splay樹上分步統計,實際上存的都是受x在splay中的子樹中的節點管轄的貢獻
ans[x] = ans[ch[x][0]] + ans[ch[x][1]] + xans[x]
+ 虛子樹中LCA爲x的:a[x]*(xsz[x]*xsz[x]-sz2[x]) (xsz[x]:x的虛子樹大小+1, sz2[x]:x的虛子樹大小平方之和)
+ 右子樹和虛子樹LCA爲x:a[x]*(2*xsz[x]*siz[ch[x][1]]) (siz[x]:真實子樹大小)
+ x及右子樹與左子樹的虛子樹LCA爲左子樹:2*all[ch[x][0]]*(siz[x]-siz[ch[x][0]]) (all[x]:x在splay子樹中節點的a*xsz之和)
在計算ans之前,先更新:
siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + xsz[x]
all[x] = all[ch[x][0]] + all[ch[x][1]] + a[x]*xsz[x]
*/