码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ2959]长跑

时间:2018-02-19 16:40:25      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:缩点   main   欧拉回路   pre   很多   blog   i++   --   cpp   

我的lct比别人慢系列...

因为边双存在欧拉回路,所以每个边双的点只要取一个就可以全取,我们可以把边双缩点,图就变成一棵树了

只有在不同的边双之间连边,缩点才会发生,关键在于怎么缩

我们可以维护一个并查集存每个点在哪个边双里,缩点时就把路径提出来,把并查集全部合并,最后更新一下缩出来的点的全职就好了

因为有了缩点,所以写lct会有微小的变化

主要是access:循环里最后一句要写成把($fa_x$所在点双编号)赋给$x$,因为把边双看作一个点;前面要更新$y$的父亲,因为之前$y$的父亲指向当前点双中的某一个点而不是点双编号$x$

写成这样就ok

void access(int x){
	int y=0;
	while(x){
		splay(x);
		rs=y;
		if(y)fa[y]=x;//更新fa[y]
		pushup(x);
		y=x;
		x=id.get(fa[x]);//用并查集找fa[x]所在点双的编号
	}
}

其他就没啥区别了,判连通性用多一个并查集会快很多然而我的代码还是那么慢

寒假都快完了我还没通永EX

#include<stdio.h>
void swap(int&a,int&b){a^=b^=a^=b;}
struct dsu{
	int fa[150010];
	int get(int x){return(x==fa[x])?x:(fa[x]=get(fa[x]));}
	void join(int x,int y){fa[get(x)]=get(y);}
}con,id;
int ch[150010][2],fa[150010],s[150010],v[150010],r[150010],val[150010];
#define ls ch[x][0]
#define rs ch[x][1]
void pushup(int x){s[x]=s[ls]+s[rs]+v[x];}
void rev(int x){
	r[x]^=1;
	swap(ls,rs);
}
void pushdown(int x){
	if(r[x]){
		if(ls)rev(ls);
		if(rs)rev(rs);
		r[x]=0;
	}
}
void rot(int x){
	int y,z,f,b;
	y=fa[x];
	z=fa[y];
	f=(ch[y][0]==x);
	b=ch[x][f];
	fa[x]=z;
	fa[y]=x;
	if(b)fa[b]=y;
	ch[x][f]=y;
	ch[y][f^1]=b;
	if(ch[z][0]==y)ch[z][0]=x;
	if(ch[z][1]==y)ch[z][1]=x;
	pushup(y);
	pushup(x);
}
bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
void gao(int x){
	if(!isrt(x))gao(fa[x]);
	pushdown(x);
}
void splay(int x){
	int y,z;
	gao(x);
	while(!isrt(x)){
		y=fa[x];
		z=fa[y];
		if(!isrt(y))rot((ch[z][0]==y&&ch[y][0]==x)||(ch[z][1]==y&&ch[y][1]==x)?y:x);
		rot(x);
	}
}
void access(int x){
	int y=0;
	while(x){
		splay(x);
		rs=y;
		if(y)fa[y]=x;
		pushup(x);
		y=x;
		x=id.get(fa[x]);
	}
}
void makert(int x){
	access(x);
	splay(x);
	rev(x);
}
void link(int x,int y){
	makert(x);
	fa[x]=y;
}
void dfs(int rt,int x){
	id.fa[x]=rt;
	if(ls)dfs(rt,ls);
	if(rs)dfs(rt,rs);
	ls=rs=0;
}
void cycle(int x,int y){
	makert(x);
	access(y);
	splay(y);
	dfs(y,y);
	v[y]=s[y];
}
void glink(int x,int y){
	x=id.get(x);
	y=id.get(y);
	if(x==y)return;
	int f1=con.get(x),f2=con.get(y);
	if(f1!=f2){
		link(x,y);
		con.join(x,y);
	}else
		cycle(x,y);
}
void add(int x,int d){
	x=id.get(x);
	splay(x);
	v[x]+=d;
	s[x]+=d;
}
int query(int x,int y){
	if(con.get(x)!=con.get(y))return-1;
	x=id.get(x);
	y=id.get(y);
	makert(x);
	access(y);
	splay(y);
	return s[y];
}
int main(){
	int n,m,i,x,y;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		scanf("%d",v+i);
		val[i]=s[i]=v[i];
		con.fa[i]=id.fa[i]=i;
	}
	while(m--){
		scanf("%d%d%d",&i,&x,&y);
		if(i==1)glink(x,y);
		if(i==2){
			add(x,y-val[x]);
			val[x]=y;
		}
		if(i==3)printf("%d\n",query(x,y));
	}
}

[BZOJ2959]长跑

标签:缩点   main   欧拉回路   pre   很多   blog   i++   --   cpp   

原文地址:https://www.cnblogs.com/jefflyy/p/8453902.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!