题目链接
不知道该如何评价这题……我觉得这种做法不是很算得上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));
}
}
}