[BZOJ2959]长跑
sol
维护点的连通关系和双连通关系,双连通分量就可以缩成一个点,开一个并查集搞一搞。
所以注意每一次跳父亲都要找他在并查集里面的根,即所有的fa[x]都要写成find(fa[x])
像这种没有cut的LCT题目最好写并查集维护连通性,常数!
code
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 150005;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
int n,m,fa[N],ch[2][N],rev[N],w[N],val[N],sum[N],con[N],scc[N],Stack[N],top;
int find(int x){return x==scc[x]?x:scc[x]=find(scc[x]);}
int Find(int x){return x==con[x]?x:con[x]=Find(con[x]);}
bool son(int x){return ch[1][find(fa[x])]==x;}
bool isroot(int x){return ch[0][find(fa[x])]!=x&&ch[1][find(fa[x])]!=x;}
void reverse(int x){if(!x)return;swap(ch[0][x],ch[1][x]);rev[x]^=1;}
void pushup(int x){sum[x]=sum[ch[0][x]]+sum[ch[1][x]]+val[x];}
void pushdown(int x){if(!rev[x])return;reverse(ch[0][x]);reverse(ch[1][x]);rev[x]=0;}
void rotate(int x)
{
int y=find(fa[x]),z=find(fa[y]),c=son(x);
ch[c][y]=ch[c^1][x];if (ch[c][y]) fa[ch[c][y]]=y;
fa[x]=z;if (!isroot(y)) ch[son(y)][z]=x;
ch[c^1][x]=y;fa[y]=x;pushup(y);
}
void splay(int x)
{
Stack[top=1]=x;
for (int y=x;!isroot(y);y=find(fa[y])) Stack[++top]=find(fa[y]);
while (top) pushdown(Stack[top--]);
for (int y=find(fa[x]);!isroot(x);rotate(x),y=find(fa[x]))
if (!isroot(y)) son(x)^son(y)?rotate(x):rotate(y);
pushup(x);
}
void access(int x){for (int y=0;x;y=x,x=find(fa[x])) splay(x),ch[1][x]=y,pushup(x);}
void makeroot(int x){access(x);splay(x);reverse(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
void dfs(int x,int rt){if(!x)return;scc[find(x)]=rt;dfs(ch[0][x],rt);dfs(ch[1][x],rt);}
int main()
{
n=gi();m=gi();
for (int i=1;i<=n;++i) con[i]=scc[i]=i,w[i]=val[i]=gi();
while (m--)
{
int opt=gi(),u=gi(),v=gi();
if (opt==1)
{
u=find(u);v=find(v);
if (Find(u)!=Find(v)) link(u,v),con[Find(u)]=Find(v);
else{
split(u,v);val[v]=sum[v];
dfs(v,v);ch[0][v]=ch[1][v]=0;
}
}
if (opt==2)
{
int fu=find(u);
splay(fu);val[fu]+=v-w[u];w[u]=v;pushup(fu);
}
if (opt==3)
{
u=find(u);v=find(v);
if (Find(u)^Find(v)) {puts("-1");continue;}
split(u,v);printf("%d\n",sum[v]);
}
}
return 0;
}