bzoj 2959: 长跑【LCT+并查集】

如果没有环的话直接LCT
考虑有环怎么办,如果是静态的话就tarjan了,但是这里要动态的缩环
具体是link操作的时候看一下是否成环(两点已联通),成环的话就用并查集把这条链缩到一个点,把权值加给祖先,断开所有splay上儿子。不过父亲这里不用管,就先让他们连着
每次操作的时候都用并查集找到支配点再进行操作
access跳父亲的时候直接跳到父亲的支配点
然后splay的时候,前面用栈倒着pushdown的时候,把所有父亲指向都改到他的支配点上,这样就相当于操作这个splay的时候只有支配点了,被支配点全都断掉了
判断联通那里,因为没有cut,所以直接用另一个并查集维护连通性比较方便

#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
int n,m,f[N],fa[N],a[N],s[N],top;
struct lct
{
	int f,c[2],s,v,lz;
}t[N];
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
int zhao(int x)
{
	return (f[x]==x)?x:f[x]=zhao(f[x]);
}
int zhaof(int x)
{
	return (fa[x]==x)?x:fa[x]=zhaof(fa[x]);
}
void ud(int x)
{
	t[x].s=t[t[x].c[0]].s+t[t[x].c[1]].s+t[x].v;
}
void pd(int x)
{
	if(t[x].lz)
	{
		swap(t[x].c[0],t[x].c[1]);
		t[t[x].c[0]].lz^=1;
		t[t[x].c[1]].lz^=1;
		t[x].lz=0;
	}
}
bool srt(int x)
{
	int fx=t[x].f;
	return t[fx].c[0]!=x&&t[fx].c[1]!=x;
}
void zhuan(int x)
{
	int y=t[x].f,z=t[y].f,l=(t[y].c[1]==x),r=l^1;
	if(!srt(y))
		t[z].c[t[z].c[1]==y]=x;
	t[x].f=z;
	t[y].c[l]=t[x].c[r];
	t[t[y].c[l]].f=y;
	t[x].c[r]=y;
	t[y].f=x;
	ud(y);
	ud(x);
}
void splay(int x)
{
	s[top=1]=x;
	for(int i=x;!srt(i);i=zhao(t[i].f))
		s[++top]=zhao(t[i].f);
	while(top)
		pd(s[top]),t[s[top]].f=zhao(t[s[top]].f),top--;
	while(!srt(x))
	{
		int y=t[x].f,z=t[y].f;
		if(!srt(y))
		{
			if((t[y].c[1]==x)^(t[z].c[1]==y))
				zhuan(x);
			else
				zhuan(y);
		}
		zhuan(x);
	}
}
void acc(int x)
{
	for(int i=0;x;i=x,x=zhao(t[x].f))
	{//cerr<<x<<" "<<i<<endl;
		splay(x);//cerr<<"OK"<<endl;
		t[x].c[1]=i;
		ud(x);
	}
}
void mkrt(int x)
{
	acc(x);
	splay(x);
	t[x].lz^=1;
}
void lk(int x,int y)
{
	mkrt(x);
	t[x].f=y;
}
void hb(int x,int fat)
{
	if(!x)
		return;
	f[zhao(x)]=fat;
	pd(x);
	if(x!=fat)
		t[fat].v+=t[x].v;
	hb(t[x].c[0],fat);
	hb(t[x].c[1],fat);
	t[x].c[0]=t[x].c[1]=0;
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)
		t[i].v=a[i]=read(),f[i]=fa[i]=i;
	while(m--)
	{
		int o=read(),x=read(),y=read();//cerr<<o<<endl;
		if(o==1)
		{
			int fx=zhao(x),fy=zhao(y);
			if(fx==fy)
				continue;
			int r1=zhaof(fx),r2=zhaof(fy);
			if(r1==r2)
			{
				mkrt(fx);
				acc(fy);
				splay(fy);
				hb(fy,fy);
				ud(fy);
			}
			else
			{//cerr<<fx<<" "<<fy<<endl;
				fa[r2]=r1;
				lk(fx,fy);
			}
		}
		else if(o==2)
		{
			int fx=zhao(x);
			acc(fx);
			splay(fx);
			t[fx].v=t[fx].v-a[x]+y;
			a[x]=y;
			ud(fx);
		}
		else
		{
			int fx=zhao(x),fy=zhao(y);//cerr<<fx<<" "<<fy<<endl;
			if(zhaof(fx)!=zhaof(fy))
				puts("-1");
			else
			{//cerr<<fx<<" "<<fy<<endl;
				mkrt(fx);//cerr<<"OK"<<endl;
				acc(fy);
				splay(fy);
				printf("%d\n",t[fy].s);
			}
		}
	}
	return 0;
}
posted @ 2019-04-18 20:24  lokiii  阅读(159)  评论(0编辑  收藏  举报