码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ3091 城市旅行 LCT

时间:2017-12-14 03:59:01      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:lld   gcd   scanf   cpp   type   put   algorithm   break   namespace   

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ3091


题意概括

  鉴于本人语文不好,此题的描述原题很清晰,废话不多,请看原题。

  可怕,原题是图片,不可以复制题目+删掉废话了……


题解

  http://blog.csdn.net/popoqqq/article/details/40823659

  这位大佬写的很好。

  我的代码在找错的时候一边找,一边该,然后发现和他改的好像……


代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long LL;
const int N=50005;
struct Gragh{
	int cnt,y[N*2],nxt[N*2],fst[N];
	void clear(){
		cnt=0;
		memset(fst,0,sizeof fst);
	}
	void add(int a,int b){
		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
	}
}g;
int n,m;
int fa[N],son[N][2],rev[N];
LL size[N],val[N],add[N],sum[N],Lsum[N],Rsum[N],Exp[N];
bool isroot(int x){
	return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
void pushup(int x){
	int ls=son[x][0],rs=son[x][1],lsz=size[ls],rsz=size[rs];
	size[x]=lsz+rsz+1;
	sum[x]=sum[ls]+sum[rs]+val[x];
	Lsum[x]=Lsum[ls]+(lsz+1)*val[x]+Lsum[rs]+sum[rs]*(lsz+1);
	Rsum[x]=Rsum[rs]+(rsz+1)*val[x]+Rsum[ls]+sum[ls]*(rsz+1);
	Exp[x]=Exp[ls]+Exp[rs]+Lsum[ls]*(rsz+1)+Rsum[rs]*(lsz+1)+val[x]*(lsz+1)*(rsz+1);
}
void pushson(int x,LL v){
	if (!x)
		return;
	val[x]+=v,sum[x]+=v*size[x],add[x]+=v;
	Lsum[x]+=v*size[x]*(size[x]+1)/2;
	Rsum[x]+=v*size[x]*(size[x]+1)/2;
	Exp[x]+=v*size[x]*(size[x]+1)*(size[x]+2)/6;
}
void pushrev(int x){
	rev[x]^=1;
	swap(son[x][0],son[x][1]);
	swap(Lsum[x],Rsum[x]);
}
void pushdown(int x){
	int &ls=son[x][0],&rs=son[x][1];
	if (rev[x]){
		rev[x]=0;
		pushrev(ls);
		pushrev(rs);
	}
	if (add[x]){
		LL &a=add[x];
		pushson(ls,a);
		pushson(rs,a);
		a=0;
	}
}
void pushadd(int x){
	if (!isroot(x))
		pushadd(fa[x]);
	pushdown(x);
}
int wson(int x){
	return son[fa[x]][1]==x;
}
void rotate(int x){
	if (isroot(x))
		return;
	int y=fa[x],z=fa[y],L=wson(x),R=L^1;
	if (!isroot(y))
		son[z][wson(y)]=x;
	fa[x]=z,fa[y]=x,fa[son[x][R]]=y;
	son[y][L]=son[x][R],son[x][R]=y;
	pushup(y),pushup(x);
}
void splay(int x){
	pushadd(x);
	for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
		if (!isroot(y))
			rotate(wson(x)==wson(y)?y:x);
}
void access(int x){
	int t=0;
	while (x){
		splay(x);
		son[x][1]=t;
		pushup(x);
		t=x;
		x=fa[x];
	}
}
void rever(int x){
	access(x);
	splay(x);
	pushrev(x);
}
void link(int x,int y){
	rever(x);
	fa[x]=y;
}
void cut(int x,int y){
	rever(x);
	access(y);
	splay(y);
	fa[x]=son[y][0]=0;
}
int find(int x){
	access(x);
	splay(x);
	while (1){
		pushdown(x);
		if (son[x][0])
			x=son[x][0];
		else
			break;
	}
	return x;
}
void dfs(int x,int pre){
	fa[x]=pre;
	for (int i=g.fst[x];i;i=g.nxt[i])
		if (g.y[i]!=pre)
			dfs(g.y[i],x);
}
LL gcd(LL a,LL b){
	return b==0?a:gcd(b,a%b);
}
void solve(int x,int y){
	if (find(x)!=find(y)){
		puts("-1");
		return;
	}
	rever(x);
	access(y);
	splay(y);
	LL a=Exp[y];
	LL b=size[y]*(size[y]+1)/2;
	LL Gcd=gcd(a,b);
	a/=Gcd,b/=Gcd;
	printf("%lld/%lld\n",a,b);
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++){
		scanf("%lld",&val[i]);
		fa[i]=son[i][0]=son[i][1]=rev[i]=0;
		size[i]=1,Exp[i]=Lsum[i]=Rsum[i]=sum[i]=val[i],add[i]=0;
	}
	g.clear();
	for (int i=1,a,b;i<n;i++){
		scanf("%d%d",&a,&b);
		g.add(a,b),g.add(b,a);
	}
	dfs(1,0);
	for (int i=1;i<=m;i++){
		int op,x,y;
		LL v;
		scanf("%d%d%d",&op,&x,&y);
		if (op==1){
			if (find(x)==find(y))
				cut(x,y);
		}
		else if (op==2){
			if (find(x)!=find(y))
				link(x,y);
		}
		else if (op==3){
			scanf("%lld",&v);
			if (find(x)!=find(y))
				continue;
			rever(x);
			access(y);
			splay(y);
			pushson(y,v);
		}
		else
			solve(x,y);
	}
	return 0;
}

  

BZOJ3091 城市旅行 LCT

标签:lld   gcd   scanf   cpp   type   put   algorithm   break   namespace   

原文地址:http://www.cnblogs.com/zhouzhendong/p/8034943.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!