【BZOJ3091】城市旅行 LCT

【BZOJ3091】城市旅行

Description

Input

Output

Sample Input

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

Sample Output

16/3
6/1

HINT

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

题解:做过不少在线段树上推式子的,但是头一次做到将式子放到树上然后用splay进行区间合并的~

$ans=\sum v[i]*dep[i]*(dep[y]-dep[i]+1)=\sum v[i]*dep[i]*(dep[y]+1)-\sum v[i]*dep[i]*dep[i]$

所以我们只需要维护v[i]*dep[i]和v[i]*dep[i]*dep[i]即可。由于我们在查询时a和b会跑到同一个splay里,所以节点i的dep就是i在splay中的中序遍历序。然后用v[i]更新v[i]*dep[i],用v[i]和v[i]*dep[i]更新v[i]*dep[i]*dep[i]即可。

但是问题来了,翻转!翻转我们怎么办?翻转操作会使所有的dep全都改变,于是我们需要维护两套v[i],v[i]*dep,v[i]*dep*dep,一套是正的,一套是反的,翻转操作时我们只需要交换这两套即可。

此外,LCT的瓶颈依然在findroot操作那里,一开始TLE,改了改姿势就过了。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=50010;
struct LCT
{
	int ch[2],fa,rev;
	ll v,ts,s0[2],s1[2],s2[2],siz;
}s[maxn];
int n,m;
bool isr(int x)	{return s[s[x].fa].ch[0]!=x&&s[s[x].fa].ch[1]!=x;}
void add(int x,ll val)
{
	s[x].v+=val,s[x].ts+=val;
	s[x].s0[0]+=s[x].siz*val,s[x].s1[0]+=s[x].siz*(s[x].siz+1)/2*val,s[x].s2[0]+=s[x].siz*(s[x].siz+1)*(2*s[x].siz+1)/6*val;
	s[x].s0[1]+=s[x].siz*val,s[x].s1[1]+=s[x].siz*(s[x].siz+1)/2*val,s[x].s2[1]+=s[x].siz*(s[x].siz+1)*(2*s[x].siz+1)/6*val;
}
void pushup(int x)
{
	s[x].siz=s[s[x].ch[0]].siz+s[s[x].ch[1]].siz+1;
	s[x].s0[0]=s[s[x].ch[0]].s0[0]+s[s[x].ch[1]].s0[0]+s[x].v;
	s[x].s1[0]=s[s[x].ch[0]].s1[0]+s[s[x].ch[1]].s1[0]+(s[s[x].ch[1]].s0[0]+s[x].v)*(s[s[x].ch[0]].siz+1);
	s[x].s2[0]=s[s[x].ch[0]].s2[0]+s[s[x].ch[1]].s2[0]+(s[s[x].ch[1]].s0[0]+s[x].v)*(s[s[x].ch[0]].siz+1)*(s[s[x].ch[0]].siz+1)+2*s[s[x].ch[1]].s1[0]*(s[s[x].ch[0]].siz+1);
	s[x].s0[1]=s[s[x].ch[1]].s0[1]+s[s[x].ch[0]].s0[1]+s[x].v;
	s[x].s1[1]=s[s[x].ch[1]].s1[1]+s[s[x].ch[0]].s1[1]+(s[s[x].ch[0]].s0[1]+s[x].v)*(s[s[x].ch[1]].siz+1);
	s[x].s2[1]=s[s[x].ch[1]].s2[1]+s[s[x].ch[0]].s2[1]+(s[s[x].ch[0]].s0[1]+s[x].v)*(s[s[x].ch[1]].siz+1)*(s[s[x].ch[1]].siz+1)+2*s[s[x].ch[0]].s1[1]*(s[s[x].ch[1]].siz+1);
}
void rever(int x)
{
	s[x].rev^=1;
	swap(s[x].ch[0],s[x].ch[1]);
	swap(s[x].s0[0],s[x].s0[1]),swap(s[x].s1[0],s[x].s1[1]),swap(s[x].s2[0],s[x].s2[1]);
}
void pushdown(int x)
{
	if(s[x].ts)
	{
		if(s[x].ch[0])	add(s[x].ch[0],s[x].ts);
		if(s[x].ch[1])	add(s[x].ch[1],s[x].ts);
		s[x].ts=0;
	}
	if(s[x].rev)
	{
		if(s[x].ch[0])	rever(s[x].ch[0]);
		if(s[x].ch[1])	rever(s[x].ch[1]);
		s[x].rev=0;
	}
}
void updata(int x)
{
	if(!isr(x))	updata(s[x].fa);
	pushdown(x);
}
void rotate(int x)
{
	int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]);
	if(!isr(y))	s[z].ch[y==s[z].ch[1]]=x;
	s[x].fa=z,s[y].fa=x,s[y].ch[d]=s[x].ch[d^1];
	if(s[x].ch[d^1])	s[s[x].ch[d^1]].fa=y;
	s[x].ch[d^1]=y;
	pushup(y),pushup(x);
}
void splay(int x)
{
	updata(x);
	while(!isr(x))
	{
		int y=s[x].fa,z=s[y].fa;
		if(!isr(y))
		{
			if((x==s[y].ch[0])^(y==s[z].ch[0]))	rotate(x);
			else	rotate(y);
		}
		rotate(x);
	}
}
void access(int x)
{
	for(int y=0;x;splay(x),s[x].ch[1]=y,pushup(x),y=x,x=s[x].fa);
}
int findr(int x)
{
	while(s[x].fa)	x=s[x].fa;
	return x;
}
void maker(int x)
{
	access(x),splay(x),rever(x);
}
void link(int x,int y)
{
	maker(x),access(y),splay(y),s[x].fa=y;
}
void cut(int x,int y)
{
	maker(x),access(y),splay(y);
	if(s[y].ch[0]==x&&!s[x].ch[1])	s[y].ch[0]=s[x].fa=0,pushup(y);
}
ll gcd(ll a,ll b)
{
	return (!b)?a:gcd(b,a%b);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
int main()
{
	//freopen("bz3091.in","r",stdin);
	n=rd(),m=rd();
	int i,a,b,c,d;
	ll t1,t2,g;
	for(i=1;i<=n;i++)	s[i].v=rd(),pushup(i);
	for(i=1;i<n;i++)	a=rd(),b=rd(),link(a,b);
	for(i=1;i<=m;i++)
	{
		d=rd(),a=rd(),b=rd();
		if(d==1)	cut(a,b);
		if(d==2)	if(findr(a)!=findr(b))	link(a,b);
		if(d==3)
		{
			c=rd();
			if(findr(a)==findr(b))	maker(a),access(b),splay(b),add(b,c);
		}
		if(d==4)
		{
			if(findr(a)!=findr(b))	printf("-1\n");
			else
			{
				maker(a),access(b),splay(b),t1=(s[b].siz+1)*s[b].s1[0]-s[b].s2[0],t2=s[b].siz*(s[b].siz+1)/2,g=gcd(t1,t2);
				printf("%lld/%lld\n",t1/g,t2/g);
			}
		}
	}
	return 0;
}
posted @ 2017-08-18 19:49  CQzhangyu  阅读(227)  评论(0编辑  收藏  举报