NOI2014魔法森林--LCT

题意:求一条1->n的路径,使得路径上的MAXA+MAXB最小。

做法:以a值从小到大对边排序,动态加边,维护一个最小生成树就行了。如果两个端点不连通,则直接加上,否则就把这个环上b值最大的边删掉,用LCT维护。

PS:UOJ上居然还有hack单旋的,太坑了。

#include
#include
#include
using namespace std;
#define REP(I,ST,ED) for(int I=ST,I##end=ED;I<=I##end;++I)
#define DREP(I,ST,ED) for(int I=ST,I##end=ED;I>=I##end;--I)
const int maxn=150005,inf=0x3f3f3f3f;
int read(){
	int x=0;
	char c=getchar();
	while((c<'0')||(c>'9'))c=getchar();
	while((c>='0')&&(c<='9'))x=x*10+c-'0',c=getchar();
	return x;
}
void read(int &a,int &b,int &c,int &d){
	a=read(),b=read(),c=read(),d=read();
}
struct Edge{
	int u,v,a,b;
	void input(){read(u,v,a,b);}
	bool operator < (const Edge &p) const {return aval[y]?x:y;
}
struct Link_Cut_Tree{
	int fa[maxn],ch[maxn][2],Max[maxn];
	bool rev[maxn];
	bool is_root(int p){
		return (p!=ch[fa[p]][0])&&(p!=ch[fa[p]][1]);
	}
	void push_up(int p){
		Max[p]=cmp_val(p,cmp_val(Max[ch[p][0]],Max[ch[p][1]]));
	}
	void push_down(int p){
		if(rev[p]){
			int &u=ch[p][0],&v=ch[p][1];
			swap(u,v),rev[u]^=1,rev[v]^=1,rev[p]=0;
		}
	}
	void push(int u){
		if(!is_root(u))push(fa[u]);
		push_down(u);
	}
	void rotate(int u){
		int p=fa[u],k=(u==ch[p][1]);
		if(!is_root(p))ch[fa[p]][p==ch[fa[p]][1]]=u;
		if(ch[u][k^1])fa[ch[u][k^1]]=p;
		ch[p][k]=ch[u][k^1],ch[u][k^1]=p;
		fa[u]=fa[p],fa[p]=u,push_up(p);
	}
	void splay(int u){
		push(u);
		for(int f=fa[u],g=fa[f];!is_root(u);rotate(u),f=fa[u],g=fa[f])
			if(!is_root(f))rotate(((u==ch[f][1])^(f==ch[g][1]))?u:f);
		push_up(u);
	}
	void access(int u){
		for(int v=0;u;u=fa[v=u])
			splay(u),ch[u][1]=v,push_up(u);
	}
	void set_root(int u){
		access(u),splay(u),rev[u]^=1;
	}
	void link(int u,int v){
		set_root(u),fa[u]=v,push_up(v);
	}
	void cut(int u,int v){
		set_root(u),access(v),splay(v);
		ch[v][0]=fa[u]=0,push_up(v);
	}
	int query(int u,int v){
		set_root(u),access(v),splay(v);
		return Max[v];
	}
}T;
int fa[maxn];
int find_fa(int x){
	if(x==fa[x])return x;
	else return fa[x]=find_fa(fa[x]);
}
void Add_Edge(int x){
	T.link(x,E[x].u+m);
	T.link(x,E[x].v+m);
}
void Del_Edge(int x){
	T.cut(x,E[x].u+m);
	T.cut(x,E[x].v+m);
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	int ans=inf,u,v,Max,tmp;
	n=read(),m=read();
	REP(i,1,n)fa[i]=i;
	REP(i,1,m)E[i].input();
	sort(E+1,E+1+m);
	REP(i,1,m){
		u=E[i].u,v=E[i].v,Max=T.query(u+m,v+m),val[i]=E[i].b;
		if(find_fa(u)!=find_fa(v))fa[find_fa(v)]=find_fa(u),Add_Edge(i);
		else if(val[Max]>val[i])Del_Edge(Max),Add_Edge(i);
		if(find_fa(1)==find_fa(n))ans=min(ans,E[i].a+val[T.query(m+1,m+n)]);
	}
	printf("%d\n",ans==inf?-1:ans);
	return 0;
}


你可能感兴趣的:(LCT)