zoukankan      html  css  js  c++  java
  • 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
    ",t[fy].s);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    新年后的第一个学习总结
    2021/02/07周学习总结
    内网穿透
    有效的括号
    实现一个简单的模板字符串替换
    二叉树的最大深度
    前端性能和错误监控
    前端缓存
    display: none; opacity: 0; visibility: hidden;
    发布订阅模式与观察者模式
  • 原文地址:https://www.cnblogs.com/lokiii/p/10732077.html
Copyright © 2011-2022 走看看