洛谷P4847 银河英雄传说V2(LCT)

题目链接
不知道该如何评价这题……我觉得这种做法不是很算得上LCT,应该只是splay
写颗假的lct,同在一个序列里的都用实边相连
每次link将第一个序列的头找到,第二个序列的尾找到,头尾之间连实边打通
每次cut直接提到根把实边直接断掉
查询的时候分别拎出两个点,做前缀和式的查询就行了,如果答案小于等于零就换下这两个点的位置
代码如下:

#include<bits/stdc++.h>
#define lson ch[x][0]
#define rson ch[x][1]
#define N 500050
using namespace std;

int n,m;
int ch[N][2],val[N],f[N],sz[N],w[N];
long long sum[N];

inline int not_root(int x)
{
	return ch[f[x]][0]==x||ch[f[x]][1]==x;
}

void push_up(int x)
{
	sum[x]=sum[lson]+sum[rson]+w[x];
}

void rotate(int x)
{
	int y=f[x],z=f[y],kd=ch[y][1]==x,xs=ch[x][!kd];
	if(not_root(y)) ch[z][ch[z][1]==y]=x;
	ch[x][!kd]=y;
	ch[y][kd]=xs;
	if(xs) f[xs]=y;
	f[x]=z,f[y]=x;
	push_up(y);
}

void splay(int x)
{
	int y,z;
	while(not_root(x))
	{
		y=f[x],z=f[y];
		if(not_root(y))
		{
			(ch[y][0]==x)^(ch[z][0]==y)?rotate(x):rotate(y);
		}
		rotate(x);
	}
	push_up(x);
}

void access(int x)
{
	for(int y=0;x;y=x,x=f[x])
	{
		splay(x);
		rson=y;
		push_up(x);
	}
}

int find_root(int x)
{
	splay(x);
	while(lson)
	{
		x=lson;
	}
	return x;
}

int find_last(int x)
{
	splay(x);
	while(rson)
	{
		x=rson;
	}
	return x;
}

void link(int x,int y)
{
	int l=find_root(x);
	if(l==find_root(y)) return ;
	int r=find_last(y);
	splay(l),f[l]=r;
	access(find_last(x));
}

void cut(int x)
{
	splay(x);
	f[lson]=0;
	lson=0;
	push_up(x);
}

long long get_ans(int x,int y)
{
	long long ans=0;
	if(find_root(x)!=find_root(y)) return -1;
	splay(x),ans-=sum[lson];
	splay(y),ans+=sum[ch[y][0]]+w[y];
	if(ans<=0)
	{
		ans=0;
		splay(y),ans-=sum[ch[y][0]];
		splay(x),ans+=sum[lson]+w[x];
	}
	return ans;
}

char op[10];
int from,to;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&w[i]);
		sum[i]=w[i];
	}
	while(m--)
	{
		scanf("%s",op);
		if(op[0]=='M')
		{
			scanf("%d%d",&from,&to);
			link(from,to);
		}
		if(op[0]=='D')
		{
			scanf("%d",&from);
			cut(from);
		}
		if(op[0]=='Q')
		{
			scanf("%d%d",&from,&to);
			printf("%lld\n",get_ans(from,to));
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值