bzoj 2959: 长跑
可以看作是这道题的加强版:https://www.luogu.org/problemnew/show/P2542
看到动态维护\(Tarjan\)缩点就考虑使用\(LCT\),使用一个并查集\(f\)表示点\(i\)所在的点双的“标志”点是哪一个,\(link\)时分类讨论一下即可
然后这题卡常,我们无法使用\(findroot\),于是考虑再用一个并查集表示两点之间的连通性即可
剩下的就和那个弱化版差不多了
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
int n,m,fa[150050],con[150050],f[150050],tag[150050],ch[150050][2];
int val[150050],sum[150050],w[150050];
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int find(int x)
{
if (f[x]==x) return x;
f[x]=find(f[x]);
return f[x];
}
int findcon(int x)
{
if (con[x]==x) return x;
con[x]=findcon(con[x]);
return con[x];
}
bool isroot(int x)
{
int fx=find(fa[x]);
return ((ch[fx][0]!=x) && (ch[fx][1]!=x));
}
void pushup(int x) {sum[x]=w[x]+sum[ch[x][0]]+sum[ch[x][1]];}
void puttag(int x) {swap(ch[x][0],ch[x][1]);tag[x]^=1;}
void pushdown(int x)
{
if (tag[x])
{
if (ch[x][0]) puttag(ch[x][0]);
if (ch[x][1]) puttag(ch[x][1]);
tag[x]=0;
}
}
void update(int x)
{
//if (x==1) cout << "NOW " << ch[x][0] << " " << ch[x][1] << endl;
if (!isroot(x)) update(find(fa[x]));pushdown(x);
}
void rotate(int x)
{
int y=find(fa[x]),z=find(fa[y]),k=(ch[y][1]==x),w=ch[x][k^1];
if (!isroot(y)) ch[z][ch[z][1]==y]=x;
ch[x][k^1]=y;ch[y][k]=w;
if (w) fa[w]=y;fa[y]=x;fa[x]=z;
pushup(y);pushup(x);
}
void splay(int x)
{
update(x);
while (!isroot(x))
{
int y=find(fa[x]),z=find(fa[y]);
if (!isroot(y))
{
if ((ch[z][1]==y)^(ch[y][1]==x)) rotate(x);else rotate(y);
}
rotate(x);
}
pushup(x);
}
void access(int x)
{
int y=0;
while (x)
{
splay(x);ch[x][1]=y;pushup(x);
y=x;fa[y]=find(fa[y]);x=find(fa[x]);
}
}
int findroot(int x)
{
access(x);splay(x);
while (ch[x][0])
{
pushdown(x);x=ch[x][0];
}
splay(x);return x;
}
void out()
{
cout <<endl;
rep(i,1,n) cout << ch[i][0] << " " << ch[i][1] <<" ";cout << endl;
cout << endl;
}
void makeroot(int x) {access(x);splay(x);puttag(x);}
void link(int x,int y) {makeroot(x);fa[x]=y;}
void split(int x,int y) {makeroot(x);access(y);splay(y);}
void cut(int x,int y) {split(x,y);ch[y][0]=0;fa[x]=0;pushup(y);}
void del(int x,int y)
{
f[x]=y;pushdown(x);
if (ch[x][0]) del(ch[x][0],y);
if (ch[x][1]) del(ch[x][1],y);
}
int main()
{
n=read();m=read();
rep(i,1,n)
{
val[i]=read();sum[i]=val[i];w[i]=val[i];
f[i]=i;con[i]=i;
}
rep(i,1,m)
{
int op=read(),x=read(),y=read();
if (op==1)
{
int fx=find(x),fy=find(y);
if (fx==fy) continue;
int cx=findcon(fx),cy=findcon(fy);
if (cx!=cy)
{
link(fx,fy);
con[cx]=cy;
}
else
{
split(fx,fy);w[fy]=sum[fy];
del(fy,fy);ch[fy][0]=0;pushup(fy);
}
}
else if (op==2)
{
int fx=find(x);splay(fx);
w[fx]+=(y-val[x]);sum[fx]+=(y-val[x]);
val[x]=y;pushup(fx);
}
else if (op==3)
{
int fx=find(x),fy=find(y);
int cx=findcon(fx),cy=findcon(fy);
if (cx!=cy) puts("-1");
else
{
split(fx,fy);
printf("%d\n",sum[fy]);
}
}
}
return 0;
}
/*
9 31
10 20 30 40 50 60 70 80 90
3 1 2
1 1 3
1 1 2
1 8 9
1 2 4
1 2 5
1 4 6
1 4 7
3 1 8
3 8 8
1 8 9
3 8 8
3 7 5
3 7 3
1 4 1
3 7 5
3 7 3
1 5 7
3 6 5
3 3 6
1 2 4
1 5 5
3 3 6
2 8 180
3 8 8
2 9 190
3 9 9
2 5 150
3 3 6
2 1 210
3 3 6
*/