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

bzoj-3091 城市旅行

时间:2015-08-18 22:48:58      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:bzoj   lct   

题意:

给出一颗树,点上有初始权值,有四种操作;

1.加一条边;

2.删一条边;

3.一条路径上的点都加一个权值;

4.查询一条路径上任取两个点的路径上期望权值和;


题解:

本题是2752的升级版,一些公式之类的东西参照上题;

到了树上之后,实际上本质的公式是没有变的,只有一些外在的形式改变了;

因为Splay维护的是树上的重链,那么结点维护的就是链上的答案等东西;

转移一样但是有几点注意;

这里选取的两个点可以相等,所以总方案数是n*(n+1)/2;

换根反转区间时,L[x]和R[x]要相应改变(其实就是交换);

别忘了输出-1的特殊情况;

然后用力码一码就可以过了;


代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 51000
#define which(x) (ch[fa[x]][1]==x)
using namespace std;
typedef unsigned long long ll;
ll fa[N],ch[N][2],size[N],sum[N],val[N],ans[N],L[N],R[N],cov[N];
bool rt[N],rev[N];
void Pushup(ll x)
{
	size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
	sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x];
	ans[x]=ans[ch[x][0]]+ans[ch[x][1]]+val[x]*(size[ch[x][0]]+1)*(size[ch[x][1]]+1)
			+L[ch[x][0]]*(size[ch[x][1]]+1)+R[ch[x][1]]*(size[ch[x][0]]+1);
	L[x]=L[ch[x][0]]+val[x]*(size[ch[x][0]]+1)+L[ch[x][1]]+sum[ch[x][1]]*(size[ch[x][0]]+1);
	R[x]=R[ch[x][1]]+val[x]*(size[ch[x][1]]+1)+R[ch[x][0]]+sum[ch[x][0]]*(size[ch[x][1]]+1);
}
void update(ll x,ll v)
{
	cov[x]+=v;
	val[x]+=v;
	sum[x]+=v*size[x];
	L[x]+=size[x]*(size[x]+1)/2*v;
	R[x]+=size[x]*(size[x]+1)/2*v;
	ans[x]+=size[x]*(size[x]+1)*(size[x]+2)/6*v;
}
void reverse(ll x)
{
	swap(ch[x][0],ch[x][1]);
	swap(L[x],R[x]);
	rev[x]^=1;
}
void Pushdown(ll x)
{
	if(rev[x])
	{
		reverse(ch[x][0]);
		reverse(ch[x][1]);
		rev[x]=0;
	}
	if(cov[x])
	{
		update(ch[x][0],cov[x]);
		update(ch[x][1],cov[x]);
		cov[x]=0;
	}
}
void down(ll x)
{
	if(!rt[x])	down(fa[x]);
	Pushdown(x);
}
void Rotate(ll x)
{
	ll f=fa[x];
	bool k=which(x);
	if(rt[f])	rt[f]=0,rt[x]=1;
	else		ch[fa[f]][which(f)]=x;
	ch[f][k]=ch[x][!k];
	ch[x][!k]=f;
	fa[ch[f][k]]=f;
	fa[x]=fa[f];
	fa[f]=x;
	Pushup(f);
	Pushup(x);
}
void Splay(ll x)
{
	down(x);
	while(!rt[x])
	{
		ll f=fa[x];
		if(rt[f])
		{
			Rotate(x);
			return ;
		}
		if(which(x)^which(f))
			Rotate(x);
		else
			Rotate(f);
		Rotate(x);
	}
}
void access(ll x)
{
	ll y=0;
	while(x)
	{
		Splay(x);
		rt[ch[x][1]]=1,rt[y]=0;
		ch[x][1]=y;
		Pushup(x);
		y=x,x=fa[x];
	}
}
void Mtr(ll x)
{
	access(x);
	Splay(x);
	reverse(x);
}
bool judge(ll x,ll y)
{
	Mtr(x);
	access(y);
	Splay(x);
	while(!rt[y])
		y=fa[y];
	return x==y;
}
void Link(ll x,ll y)
{
	Mtr(x);
	fa[x]=y;
}
void Cut(ll x,ll y)
{
	Mtr(x);
	access(y);
	Splay(x);
	if(ch[x][1]==y&&!size[ch[y][0]])
	{
		ch[x][1]=fa[y]=0;
		rt[y]=1;
		Pushup(x);
	}
}
void add(ll x,ll y,ll v)
{
	Mtr(x);
	access(y);
	Splay(x);
	update(x,v);
}
ll query(ll x,ll y)
{
	Mtr(x);
	access(y);
	Splay(x);
	return ans[x];
}
ll gcd(ll a,ll b)
{
	ll t=a%b;
	while(t)
	{
		a=b,b=t;
		t=a%b;
	}
	return b;
}
int main()
{
	ll n,m,i,j,k,op,x,y,v;
	scanf("%llu%llu",&n,&m);
	for(i=1;i<=n;i++)
	{
		scanf("%llu",&v);
		val[i]=sum[i]=v;
		L[i]=R[i]=ans[i]=v;
		size[i]=rt[i]=1;
	}
	for(i=1;i<n;i++)
	{
		scanf("%llu%llu",&x,&y);
		Link(x,y);
	}
	for(i=1;i<=m;i++)
	{
		scanf("%llu",&op);
		switch(op)
		{
			case 1:
				scanf("%llu%llu",&x,&y);
				Cut(x,y);
				break;
			case 2:
				scanf("%llu%llu",&x,&y);
				if(!judge(x,y))	Link(x,y);
				break;
			case 3:
				scanf("%llu%llu%llu",&x,&y,&v);
				if(judge(x,y))	add(x,y,v);
				break;
			case 4:
				scanf("%llu%llu",&x,&y);
				if(!judge(x,y))
					puts("-1");
				else
				{
					ll u=query(x,y),d=size[x]*(size[x]+1)/2;
					ll g=gcd(u,d);
					printf("%llu/%llu\n",u/g,d/g);
				}
		}
	}
	return 0;
}



bzoj-3091 城市旅行

标签:bzoj   lct   

原文地址:http://blog.csdn.net/ww140142/article/details/47760323

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