博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

洛谷.U19464.山村游行wander(LCT 伪期望)

题目链接

题意: 森林,动态建边、删边,询问从\(S\)开始走到\(T\)的期望时间。走位: 每次人会随机地选一条未走过的边走,走到无路可走,再退回。这样直到终点T。走一条边、从一条边退回都花费时间\(1\)

题目特点是走到一棵子树一定会全走完,且是两遍的值。画个图,可以看出这一过程是:
\(S\)开始,随机走到通往\(T\)的边或\(S\)的一棵子树,走\(S\)的子树\(i\)的期望为 \(2*p[i]*sz[i]\)(来回走);
\(S\to T\)的路径上,可能会随机走到一棵子树中,期望同样为 \(2*p[i]*sz[i]\)
于是总期望为 \(Ans = ∑_{S的子树i}2*p[i]*sz[i] + ∑_{路径上的子树}2*p[i]*sz[i]\)
(这有图)
那么这个概率\(p[i]\)是多少呢,就是\(\frac12\)啊。。不同子树间一点影响没有。
所以 \(Ans = ∑_{S的子树i}sz[i] + ∑_{路径上的子树i}sz[i]\). \(LCT\)维护子树\(sz\)就行了。(小数是唬人的)
输出的话,就输出 \(树的大小-sz_i[T]-1\) 或是 以\(T\)为根的左子树大小(到\(T\)的路径其实还有\(1\),但是已经算上\(S\)\(1\)\(sz\)了)。

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=1e5+5;

namespace LCT
{
	#define lson son[x][0]
	#define rson son[x][1]

	int fa[N],son[N][2],sz[N],sz_i[N],sk[N];
	bool tag[N];
	inline void Update(int x){
		sz[x]=sz[lson]+sz[rson]+sz_i[x]+1;
	}
	inline bool n_root(int x){
		return son[fa[x]][0]==x||son[fa[x]][1]==x;
	}
	inline void Rev(int x){
		std::swap(lson,rson), tag[x]^=1;
	}
	inline void PushDown(int x){
		if(tag[x]) Rev(lson),Rev(rson),tag[x]=0;
	}
	void Rotate(int x)
	{
		int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
		if(n_root(a)) son[b][son[b][1]==a]=x;
		if(son[x][r]) fa[son[x][r]]=a;
		fa[a]=x, fa[x]=b, son[a][l]=son[x][r], son[x][r]=a;
		Update(a);
	}
	void Splay(int x)
	{
		int t=1,a=x; sk[1]=x;
		while(n_root(a)) sk[++t]=a=fa[a];
		while(t) PushDown(sk[t--]);
		while(n_root(x))
		{
			if(n_root(a=fa[x])) Rotate(son[a][1]==x^son[fa[a]][1]==a?x:a);
			Rotate(x);
		}
		Update(x);
	}
	void Access(int x){
		for(int pre=0; x; x=fa[pre=x])
			Splay(x), sz_i[x]+=sz[rson]-sz[pre], rson=pre;//Update(x);
	}
	void Make_root(int x){
		Access(x), Splay(x), Rev(x);
	}
	void Split(int x,int y){
		Make_root(x), Access(y), Splay(y);
	}
	int Find_root(int x)
	{
		Access(x), Splay(x);
		while(lson) x=lson;
		return x;
	}
	bool pre_Link(int x,int y){
		Make_root(x);//Split(x,y); //已Find_root(y)
		return Find_root(y)==x;
	}
	void Link(int x,int y){
		sz_i[y]+=sz[x], fa[x]=y, Update(y);
	}
	bool pre_Cut(int x,int y){
		Make_root(x);
		return Find_root(y)==x&&fa[x]==y&&!rson;
	}
	void Cut(int x,int y){
		fa[x]=son[y][0]=0, Update(y);
	}
	int Query(int x,int y){//已pre_Link():Make_root(x), Access(y), Splay(y).
		return sz[son[y][0]];//return sz[y]-sz_i[y]-1;
	}
}
inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}

int main()
{
	int n=read(),q=read(),opt,x,y;
	while(q--)
	{
		opt=read(),x=read(),y=read();
		if(!opt){
			if(LCT::pre_Link(x,y)) puts("ILLEGAL");
			else LCT::Link(x,y), puts("OK");
		}
		else if(opt==1){
			if(!LCT::pre_Cut(x,y)) puts("ILLEGAL");
			else LCT::Cut(x,y),puts("OK");
		}
		else if(LCT::pre_Link(x,y)) printf("%d.0000\n",LCT::Query(x,y));
		else puts("ILLEGAL");
	}
	return 0;
}
posted @ 2018-03-24 07:44  SovietPower  阅读(199)  评论(0编辑  收藏  举报