ELCA
给一棵(n)个点以(1)为根的树,每个点有权值(s_i),支持两种操作:
-
把(x)及其子树连到(y)上。
-
令(s_x=v)。
每次操作后都询问expected value written on the lowest common ancestor of two equiprobably selected vertices (i) and (j). Please note that the vertices (i) and (j) can be the same (in this case their lowest common ancestor coincides with them).
(nleq 5 imes 10^4)。
题解
没人看得懂的题解:https://www.cnblogs.com/suncongbo/p/11330695.html
表面上是期望问题,实际上是计数问题。统计节点(i)作为LCA的次数即可。
注意到
所以有
所以对树(T)我们需要维护
LCT维护子树信息的时候,Splay里面要按照中序遍历所确定的链来维护。我一稿居然按照Splay的二叉树关系维护了……
考虑push_up
的时候发生的事。带imag_
前缀的表示虚子树的信息。
-
首先是( ext{siz}_{T(x)})的维护。(T(x))代表(x)在Splay里的子树的中序遍历所确定的实链加上它们的虚子树构成的树。
[ ext{siz}_{T(x)}= ext{siz}_{T( ext{rc})}+ ext{imag_siz}_x+1+ ext{siz}_{T( ext{lc})} ] -
其次是(A_{T(x)})的维护。(x)自己的贡献和(x)右子树的贡献比较好算,但是(x)在Splay中左子树里的节点(在实链上的)就不一样了,因为它们的子树大小都发生了变化。考虑变化量,(s_i( ext{siz}_i+Delta)^2-s_i ext{siz}_i^2=s_iDelta^2+2s_i ext{siz}_iDelta),所以我们还要维护Splay链上(不包含虚子树)的(s_x)和(s_x ext{siz}_x)的和。对实链(L)记
[egin{gather} ext{sum_s}_L=sum_{iin L}s_i\ A'_L=sum_{iin L}s_i ext{siz}_i end{gather} ]令(Delta= ext{siz}_{T( ext{rc})}+1+ ext{imag_siz}_x),那么有
[egin{gather} ext{sum_s}_{L(x)}= ext{sum_s}_{L( ext{rc})}+s_x+ ext{sum_s}_{L( ext{lc})}\ A'_{L(x)}=A'_{L( ext{rc})}+s_xDelta+A'_{L( ext{lc})}+ ext{sum_s}_{L( ext{lc})}Delta\ A_{T(x)}=A_{T( ext{rc})}+ ext{imag_A}_x+s_xDelta^2+A_{T( ext{lc})}+2A'_{L( ext{lc})}Delta+ ext{sum_s}_{L( ext{lc})}Delta^2 end{gather} ] -
最后是(B_{T(x)})的维护。同样考虑(x)在Splay中左子树里的节点,它们的变化量要诡异一点,不过跟(A)大同小异。记( ext{son}_i)表示节点(i)在实链剖分中的重儿子,
[egin{gather} B'_L=sum_{iin L}s_i ext{siz}_{ ext{son}_i} end{gather} ]那么有
[egin{gather} B'_{L(x)}=B'_{L( ext{rc})}+s_x ext{siz}_{T( ext{rc})}+B'_{L( ext{lc})}+ ext{sum_s}_{T( ext{lc})}Delta\ B_{T(x)}=B_{T( ext{rc})}+ ext{imag_B}_x+s_x( ext{imag_sq_siz}_x+ ext{siz}_{T( ext{rc})}^2)+B_{T( ext{lc})}+2B'_{L( ext{lc})}Delta+ ext{sum_s}_{L( ext{lc})}Delta^2 end{gather} ]
当然了,为了支持reverse
操作,我们还需要对(A,B,A',B')维护一个合并方向相反的值。
维护好这些,易得答案( ext{ans}=frac{1}{n^2}(A_{T( ext{root})}-B_{T( ext{root})}))。
你已经完全会了,快点开始写bug吧!
时间复杂度(O(nlog n)),但常数估计都抵一个log了。
#include<bits/stdc++.h>
using namespace std;
using int64=long long;
template<class T>
T read(){
T x=0;char w=1,c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*w;
}
template<class T>
T& read(T& x){
return x=read<T>();
}
constexpr int N=5e4+10;
int ch[N][2],fa[N],rev[N];
int64 siz[N],imag_siz[N],imag_sq_siz[N];
int64 s[N],sum_s[N];
int64 A[N][2],A1[N][2],imag_A[N]; // A1 -> A'
int64 B[N][2],B1[N][2],imag_B[N]; // B1 -> B'
#define lc ch[x][0]
#define rc ch[x][1]
// helper function
bool nroot(int x){
return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
void push_up(int x){
siz[x]=siz[rc]+imag_siz[x]+1+siz[lc];
sum_s[x]=sum_s[rc]+s[x]+sum_s[lc];
// right -> left
int64 D=siz[rc]+1+imag_siz[x];
A1[x][0]=A1[rc][0]+s[x]*D+A1[lc][0]+sum_s[lc]*D;
A[x][0]=A[rc][0]+imag_A[x]+s[x]*D*D+A[lc][0]+2*A1[lc][0]*D+sum_s[lc]*D*D;
B1[x][0]=B1[rc][0]+s[x]*siz[rc]+B1[lc][0]+sum_s[lc]*D;
B[x][0]=B[rc][0]+imag_B[x]+s[x]*(imag_sq_siz[x]+siz[rc]*siz[rc])+B[lc][0]+2*B1[lc][0]*D+sum_s[lc]*D*D;
// left -> right
D=siz[lc]+1+imag_siz[x];
A1[x][1]=A1[lc][1]+s[x]*D+A1[rc][1]+sum_s[rc]*D;
A[x][1]=A[lc][1]+imag_A[x]+s[x]*D*D+A[rc][1]+2*A1[rc][1]*D+sum_s[rc]*D*D;
B1[x][1]=B1[lc][1]+s[x]*siz[lc]+B1[rc][1]+sum_s[rc]*D;
B[x][1]=B[lc][1]+imag_B[x]+s[x]*(imag_sq_siz[x]+siz[lc]*siz[lc])+B[rc][1]+2*B1[rc][1]*D+sum_s[rc]*D*D;
}
void reverse(int x){
swap(A1[x][0],A1[x][1]);
swap(A[x][0],A[x][1]);
swap(B1[x][0],B1[x][1]);
swap(B[x][0],B[x][1]);
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
void push_down(int x){
if(rev[x]){
if(ch[x][0]) reverse(ch[x][0]);
if(ch[x][1]) reverse(ch[x][1]);
rev[x]=0;
}
}
// basic operation
void rotate(int x){
int y=fa[x],z=fa[y],l=x==ch[y][1],r=l^1;
if(nroot(y)) {ch[z][y==ch[z][1]]=x;} fa[x]=z;
ch[y][l]=ch[x][r],fa[ch[x][r]]=y;
ch[x][r]=y,fa[y]=x;
push_up(y);
}
void update(int x){
if(nroot(x)) update(fa[x]);
push_down(x);
}
void splay(int x){
update(x);
for(;nroot(x);rotate(x)){
int y=fa[x],z=fa[y];
if(nroot(y)) rotate((x==ch[y][1])!=(y==ch[z][1])?x:y);
}
push_up(x);
}
void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x);
imag_siz[x]+=siz[ch[x][1]]-siz[y];
imag_sq_siz[x]+=siz[ch[x][1]]*siz[ch[x][1]]-siz[y]*siz[y];
imag_A[x]+=A[ch[x][1]][0]-A[y][0];
imag_B[x]+=B[ch[x][1]][0]-B[y][0];
ch[x][1]=y;
push_up(x);
}
}
// advanced operation
void make_root(int x){
access(x),splay(x),reverse(x);
}
int find_root(int x){
access(x),splay(x);
while(ch[x][0]) x=ch[x][0];
splay(x);
return x;
}
void split(int x,int y){
make_root(x),access(y),splay(y);
}
void link(int x,int y){
make_root(x),access(y),splay(y);
imag_siz[y]+=siz[x];
imag_sq_siz[y]+=siz[x]*siz[x];
imag_A[y]+=A[x][0];
imag_B[y]+=B[x][0];
fa[x]=y;
push_up(y);
}
void cut(int x,int y){
split(x,y);
fa[x]=ch[y][0]=0;
push_up(y);
}
int main(){
int n=read<int>(),p[N];
for(int i=2;i<=n;++i) read(p[i]);
for(int i=1;i<=n;++i) read(s[i]),push_up(i);
for(int i=2;i<=n;++i) link(i,p[i]);
make_root(1);
printf("%.9lf
",1.0*(A[1][0]-B[1][0])/n/n);
for(int q=read<int>();q--;){
char o[2];
scanf("%s",o);
if(o[0]=='P'){
int x=read<int>(),y=read<int>();
make_root(1),access(y),splay(y);
int i=x;
while(nroot(i)) i=fa[i];
if(i==y) swap(x,y);
access(x),splay(x);
fa[ch[x][0]]=0,ch[x][0]=0;
push_up(x);
link(x,y);
}
else{
int x=read<int>();
make_root(x);
read(s[x]);
push_up(x);
}
make_root(1);
printf("%.9lf
",1.0*(A[1][0]-B[1][0])/n/n);
}
return 0;
}