CF482E ELCA

XXIV.CF482E ELCA

Difficulty 3200的大神题。

这题维护应该很好想:与其维护所有对的LCA,不如维护一个数是多少对的LCA。显然,这个数量应该为\(sz_x^2-\sum\limits_{y\in son_x}sz_y^2\)。其中\(sz_x\)\(x\)子树的大小,\(son_x\)\(x\)的儿子集合。

然后套LCT。我们需要维护这样一些东西:

\(szi\):虚子树的\(sz\)

\(szr\):实子树的\(sz\)

\(sumi\):虚子树的答案和

\(sumr\):实子树的答案和

\(sqi\):虚子树的平方和

\(val\):节点的值

\(all\)

定义比较复杂。以节点\(i\)为根的实子树,是以(以节点\(i\)为根的splay中所有节点的虚子树)的并集。则\(all_x\)的定义是这些虚子树的\(szi\)乘上虚子树的根的\(val\)的和。

为什么我们要有这么个鬼东西?

因为,左儿子实际上是\(x\)的祖先。这些东西要在求左儿子的贡献时用上。

维护:

\(szr_x=szi_x+szr_{lson}+szr_{rson}\)

\(all_x=all_{lson}+all_{rson}+szi_x*val_x\)

重头戏来了:

\(sum_x=\)

\(sum_{lson}+sum_{rson}\)(子节点的\(sum\)传递上来)

\(+val_x*(szi_x^2-sqi_x)\) (虚子树的贡献)

\(+2*val_x*szi_x*szr_{rson}\) (右儿子的贡献,虚子树中任何一个点与右儿子实子树中任何一个点的LCA都是\(x\)

\(+2*all_{lson}*(szr_x-szr_{lson})\) (虚子树和右子树里面任何一个点,在原树中都是左子树中点的子孙。故\(all_x\)对于左子树中每一个点都已经储存下来了贡献,再乘上虚子树+右子树的贡献,即是正确贡献)

然后这题并不需要换根。因此实际上treap什么的也可以胜任这道题?

这题之所以difficulty 3200,我估计八成是因为这个pushup太毒瘤了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,head[50100],cnt,FA[50100],res;
#define lson t[x].ch[0]
#define rson t[x].ch[1]
struct LCT{
	int fa,ch[2],val,szi,szr,sqi,sumi,sumr,all;
}t[50100];
inline int identify(int x){
	if(x==t[t[x].fa].ch[0])return 0;
	if(x==t[t[x].fa].ch[1])return 1;
	return -1;
}
inline void pushup(int x){
	t[x].szr=t[x].szi+t[lson].szr+t[rson].szr,t[x].sumr=t[x].sumi+t[lson].sumr+t[rson].sumr;
	t[x].all=t[lson].all+t[rson].all+t[x].szi*t[x].val;
	t[x].sumr+=t[x].val*(t[x].szi*t[x].szi-t[x].sqi);
	t[x].sumr+=2*t[x].val*t[x].szi*t[rson].szr;
	t[x].sumr+=2*t[lson].all*(t[x].szr-t[lson].szr); 
}
inline void rotate(int x){
	register int y=t[x].fa;
	register int z=t[y].fa;
	register int dirx=identify(x);
	register int diry=identify(y);
	register int b=t[x].ch[!dirx];
	if(diry!=-1)t[z].ch[diry]=x;t[x].fa=z;
	if(b)t[b].fa=y;t[y].ch[dirx]=b;
	t[y].fa=x,t[x].ch[!dirx]=y;
	pushup(y),pushup(x);
}
inline void splay(int x){
	while(identify(x)!=-1){
		register int fa=t[x].fa;
		if(identify(fa)==-1)rotate(x);
		else if(identify(x)==identify(fa))rotate(fa),rotate(x);
		else rotate(x),rotate(x);
	}
}
inline void access(int x){
	for(register int y=0;x;x=t[y=x].fa){
		splay(x);
		t[x].sqi+=t[rson].szr*t[rson].szr;
		t[x].sumi+=t[rson].sumr;
		t[x].szi+=t[rson].szr;
		rson=y;
		t[x].sqi-=t[rson].szr*t[rson].szr;
		t[x].sumi-=t[rson].sumr;
		t[x].szi-=t[rson].szr;
		pushup(x);
	}
}
struct Edge{
	int to,next;
}edge[50100];
void ae(int u,int v){
	edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
}
void dfs(int x){
	t[x].szi=1;
	for(int i=head[x];i!=-1;i=edge[i].next)dfs(edge[i].to),t[x].szi+=t[edge[i].to].szr,t[x].sumi+=t[edge[i].to].sumr,t[x].sqi+=t[edge[i].to].szr*t[edge[i].to].szr;
	pushup(x);
}
void cut(int x){
	access(FA[x]),splay(FA[x]),splay(x);
	t[x].fa=0;
	t[FA[x]].szi-=t[x].szr;
	t[FA[x]].sumi-=t[x].sumr;
	t[FA[x]].sqi-=t[x].szr*t[x].szr;
	pushup(FA[x]);
}
void link(int x,int y){
	access(y),splay(y),access(x),splay(x);
	t[y].fa=x;
	t[t[y].fa].szi+=t[y].szr;
	t[t[y].fa].sumi+=t[y].sumr;
	t[t[y].fa].sqi+=t[y].szr*t[y].szr;
	pushup(t[y].fa);	
}
bool che(int x,int y){
	access(y),splay(y),splay(x);
	return identify(y)!=-1;
}
void qwq(int x,int y){
	if(FA[x]==y||FA[y]==x)return;
	if(che(x,y))swap(x,y);
	cut(x);
	FA[x]=y;
	link(y,x);
}
void qaq(int x,int y){
	access(x),splay(x),t[x].val=y,pushup(x);
}
inline void read(int &x){
	x=0;
	char c=getchar();
	while(c>'9'||c<'0')c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
}
signed main(){
	read(n),memset(head,-1,sizeof(head));
	for(int i=2;i<=n;i++)read(FA[i]),ae(FA[i],i),t[i].fa=FA[i];
	for(int i=1;i<=n;i++)read(t[i].val),t[i].szi=1;
	dfs(1),res=t[1].sumr,printf("%.9lf\n",1.0*res/(n*n));
//	for(int j=1;j<=n;j++)printf("(F:%d,L:%d,R:%d,SQ:%d,AI:%d,AR:%d,SI:%d,SR:%d,V:%d)\n",t[j].fa,t[j].ch[0],t[j].ch[1],t[j].sqi,t[j].sumi,t[j].sumr,t[j].szi,t[j].szr,t[j].val);
	scanf("%d",&m);
	for(int i=1,x,y;i<=m;i++){
		char s[3];
		scanf("%s",s),read(x),read(y);
		if(s[0]=='P')qwq(x,y);
		else qaq(x,y);
		access(1),splay(1),res=t[1].sumr;
		printf("%.9lf\n",1.0*res/(n*n));
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Troverld/p/14602221.html