城市旅行[LCT]

题目描述

W国地人物博,有n座城市组成,共n-1条双向道路连接其中的两座城市,且任意两座城市都可相互到达。

风景秀美的w国吸引了无数慕名而来的游客,根据游客对每座城市的打分,我们定义第i座城市的美丽度为a_i。一次从城市x到城市y的旅行,所获得的的偷悦指数为从城市x到城市y所有城市的美丽度之和(包括X和y)。我们诅义这个值为H(x,y)。

现在小A在城市X,Sharon在城市Y,他们想知道如果在城市X到城市Y之间的所有城市中任选两座城市x和y(x可以等于y),那么H(x,y)的期望值是多少,我们记这个期望值为E(x,y)。

当然,城市之间的交通状况飘忽不定,因此我们不能排除某些时刻某些道路将无法通行。某些时刻会突然添加新的道路。以及游客们审美观的改变,某些城市的美丽度也会发现变化。作为W国负责旅游行业的T君,他要求你来写一个程序来模拟上而的所有过程

输入格式:

第一行两个整数,n,m表示城市个数和操作个数。

接下来一行n个整数,第i个表示a_i。 接下来n-1行,每行两个整数u,v,表示u和v之间有一条路。 接下来m行,是进行下面的操作:

  • 1 u v 如果城市u和城市v已经无直接连接的道路,则忽略这个操作,否则删除u,v之间的道路。
  • 2 u v 如果城市u和城市v联通那么忽略。否则在u,v之间添加一条道路。
  • 3 u v d 如果城市u和城市v不连通,那么忽略。否则将城市u到城市v的路径中所有城市(包括u和v)的美丽度都增加d。
  • 4 u v 询问E(u,v)的值

输出格式:

对于操作4,输出答案,一个经过化简的分数p/q。如果u和v不连通输出-1。

输入样例#1: 

4 5
1 3 2 5
1 2
1 3
2 4
4 2 4
1 2 4
2 3 4
3 1 4 1
4 1 4

输出样例#1: 

16/3
6/1

对于所有数据满足 1<=N<=50,000 1<=M<=50,000 1<=a_i<=10^6 1<=D<=100 1<=U,V<=N


题意:

1.Cut(x,y)  [基本操作]

2.Link(x,y)  [基本操作]

3.修改x到y的路径   [(Makeroot(x),Access(y),Splay(y))即为x到y的路径]    [基本操作]

4.问概率 ... emmm 不是基本操作耶


我们发现对于每一个询问的概率

分母一定是 t[x].size* (t[x].size+1) / 2 因为每个点跟另一个(包涵自己)组合 有n*(n+1)/2种

分子怎么办

我们考虑一个点对多少个询问有贡献 ... 什么意思呢

比如说从x到y的路径的点权:

1 4 3 2 

共有4*5/2=10种组合:

(1,1),(1,2),(1,3),(1,4)

(2,2),(2,3),(2,4)

(3,3),(3,4)

(4,4)

其中节点1的贡献是 1*4*点权1

节点2的贡献是6*点权2  (注意1到3也经过了2) 

....

我们发现1的贡献为1 * n * 点权1

2的贡献为 2 * (n-1) * 点权2

....

n的贡献为n * 1 * 点权n

原网:https://blog.csdn.net/popoqqq/article/details/40823659


如何维护

 

3其实就是size[rc]+1

于是我们令lsum=1*a1+2*a2+...+n*an,同理有rsum=1*an+2*an-1+...+n*a1

维护exp

t[x].exp = t[lc].exp + t[rc].exp + 
t[lc].lsum * (t[rc].size+1) + t[rc].rsum * (t[lc].size+1) + 
t[x].val * (t[lc].size+1) * (t[rc].size+1); 

维护lsum,rsum

	t[x].lsum = t[lc].lsum + t[x].val * (t[lc].size+1) + t[rc].lsum + t[rc].sum * (t[lc].size+1);
	t[x].rsum = t[rc].rsum + t[x].val * (t[rc].size+1) + t[lc].rsum + t[lc].sum * (t[rc].size+1);

如何修改

把x-y的路径+val

相当于Makeroot(x) 后 Access(y),Splay(y)

将y的整颗子树+val

lsum 相当于加了(1+2+...+size(y)) * val

exp 相当于加了 x * (1*n +2*(n-1) +...) = x * n * (n+1) * (n+2)/6 (n为size(y))


代码

/*
lsum -> a[1]*1 + a[2]*2 + ... + a[n]*n
rsum -> a[n]*1 + a[n-1]*2 + ... + a[1]*n
exp ->  t[root].exp = t[ls].exp + t[rs].exp + 
t[ls].lsum * (t[rs].size+1) + t[rs].rsum * (t[ls].size+1) + x * (t[ls].size+1) * (t[rs].size + 1)

Modify --->
sum + = x*size
lsum + = x * 1 + x * 2 + x * 3 + ... + x * size = x * size * (size+1) /2
rsum ...
exp + = x * size * size+1 * size+2 /6  
*/
#include<bits/stdc++.h>
#define N 200005
#define LL long long
#define lc t[x].ch[0]
#define rc t[x].ch[1]
using namespace std;
struct Node{
	int ch[2],fa,tag;
	LL size,val,sum,lsum,rsum,exp,lazy;
}t[N];
int n,m;
int read(){
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
	return cnt*f;
}
LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
bool isRoot(int x){
	int fa=t[x].fa; if(fa==0) return true;
	return t[fa].ch[0]!=x && t[fa].ch[1]!=x;
}
void Update_sum(int x,LL val){
	t[x].val += val; 
	t[x].lazy += val;
	t[x].sum += t[x].size * val;
	t[x].lsum += val * t[x].size * (t[x].size+1) / 2;
	t[x].rsum += val * t[x].size * (t[x].size+1) / 2;
	t[x].exp += val * t[x].size * (t[x].size+1) * (t[x].size+2) / 6;
}
void Pushup(int x){
	t[x].size = t[lc].size + t[rc].size+1;
	t[x].sum = t[lc].sum + t[rc].sum + t[x].val;
	t[x].lsum = t[lc].lsum + t[x].val * (t[lc].size+1) + t[rc].lsum + t[rc].sum * (t[lc].size+1);
	t[x].rsum = t[rc].rsum + t[x].val * (t[rc].size+1) + t[lc].rsum + t[lc].sum * (t[rc].size+1);
	t[x].exp = t[lc].exp + t[rc].exp + t[lc].lsum * (t[rc].size+1) + t[rc].rsum * (t[lc].size+1) + t[x].val * (t[lc].size+1) * (t[rc].size+1); 
}
void rever(int x){
	swap(lc,rc); swap(t[x].lsum,t[x].rsum); t[x].tag^=1;
}
void Pushdown(int x){
	if(t[x].tag){
		rever(lc),rever(rc);
		t[x].tag=0;
	}
	if(t[x].lazy){
		Update_sum(lc,t[x].lazy);
		Update_sum(rc,t[x].lazy);
		t[x].lazy=0;
	}
}
void Pushpath(int x){
	if(!isRoot(x)) Pushpath(t[x].fa);
	Pushdown(x);
}
void rotate(int x){
	int y=t[x].fa,z=t[y].fa;
	int k=t[y].ch[1]==x;
	if(!isRoot(y)) t[z].ch[t[z].ch[1]==y]=x;
	t[x].fa=z;
	t[y].ch[k]=t[x].ch[k^1];
	t[t[x].ch[k^1]].fa=y;
	t[x].ch[k^1]=y,t[y].fa=x;
	Pushup(y),Pushup(x);
}
void Splay(int x){
	Pushpath(x);
	while(!isRoot(x)){
		int y=t[x].fa,z=t[y].fa;
		if(!isRoot(y)) 
			(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
		rotate(x);
	}Pushup(x);
}
void Access(int x){
	for(int y=0;x;y=x,x=t[x].fa)
		Splay(x),t[x].ch[1]=y,Pushup(x);
}
int Findroot(int x){
	Access(x),Splay(x);
	while(lc) Pushdown(x),x=lc;
	return x;
}
void Makeroot(int x){
	Access(x),Splay(x),rever(x);
}
void Link(int x,int y){
	Makeroot(x),t[x].fa=y;
}
void Cut(int x,int y){
	Makeroot(x),Access(y),Splay(y);
	t[y].ch[0]=0,t[x].fa=0,Pushup(y);
}
void Add(int x,int y){
	int val=read();
	if(Findroot(x)!=Findroot(y)) return;
	Makeroot(x),Access(y),Splay(y);
	Update_sum(y,val);
} 
void Get_ans(int x,int y){
	if(Findroot(x)!=Findroot(y)){printf("-1\n");return;}
	Makeroot(x),Access(y),Splay(y);
	LL a=t[y].exp,b=t[y].size*(t[y].size+1)/2;
	LL g=gcd(a,b);
	printf("%lld/%lld\n",a/g,b/g);
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		int x=read(); t[i].size=1;
		t[i].val=t[i].sum=t[i].lsum=t[i].rsum=t[i].exp=x;
	}
	for(int i=1;i<=n-1;i++){int x=read(),y=read(); Link(x,y);}
	while(m--){
		int op=read(),x=read(),y=read();
		if(op==1) if(Findroot(x)==Findroot(y)) Cut(x,y);
		if(op==2) if(Findroot(x)!=Findroot(y)) Link(x,y);
		if(op==3) Add(x,y);
		if(op==4) Get_ans(x,y);
	}
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/83004806
LCT