P2387-[NOI2014]魔法森林【LCT】

前言

话说 L C T LCT S p l a y Splay 和平时写的 S p l a y Splay 差别好大,调了我半天


正题

题目链接:[https://www.luogu.com.cn/problem/P2387


题目大意

n n 个点 m m 条边有 a , b a,b 两个值,求一条路径从 1 > n 1->n 使得路径上最大的 a a 加上最大的 b b 最小。


解题思路

我们可以将边按照 a a 排序,然后枚举最大的 a a 值。此时我们需要维护 1 > n 1->n 路径上最小的 b b 值,要支持动态插边。

考虑使用 L C T LCT ,对于一条 ( x , y , w ) (x,y,w) 的边,我们查询目前 x , y x,y 之间路径上的最大边,如果该值比 w w 大,我们断开最大边,连接该边,否则不连接即可。


c o d e code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct node{
	int x,y,a,b;
}a[N];
int n,m,val[N],sum[N],from[N],fa[N],ans;
struct Line_Cut_Tree{
	#define ls t[x][0]
	#define rs t[x][1]
	int t[N][2],fa[N];
	bool r[N];
	void PushR(int x)
	{r[x]^=1;swap(ls,rs);}
	void PushDown(int x)
	{if(r[x]){r[x]=0;PushR(ls);PushR(rs);}}
	bool Nroot(int x)
	{return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}
	void PushUp(int x)
	{
		sum[x]=val[x];from[x]=x;
		if(ls&&sum[ls]>sum[x]) 
			sum[x]=sum[ls],from[x]=from[ls];
		if(rs&&sum[rs]>sum[x]) 
			sum[x]=sum[rs],from[x]=from[rs];
	}
	void Rotate(int x){
		int y=fa[x],z=fa[y],k=(t[y][1]==x),w=t[x][!k];
		if(Nroot(y)) t[z][t[z][1]==y]=x;
		t[x][!k]=y;t[y][k]=w;
		if(w) fa[w]=y;fa[y]=x;fa[x]=z;
		PushUp(y);PushUp(x);
		return;
	}
	void Updata(int x)
	{
		if(Nroot(x))Updata(fa[x]);
		PushDown(x);
	}
	void Splay(int x){
		int y=x,z=0;
		Updata(x);
		while(Nroot(x)){
			y=fa[x];z=fa[y];
			if(Nroot(y))
				Rotate((t[y][0]==x)^(t[z][0]==y)?x:y);
			Rotate(x);
		}
		PushUp(x);
		return;
	}
	void Access(int x)
	{
		for(int y=0;x;x=fa[y=x])
			Splay(x),rs=y,PushUp(x);
		return;
	}
	void MakeRoot(int x)
	{Access(x);Splay(x);PushR(x);return;}
	int Split(int x,int y)
	{MakeRoot(x);Access(y);Splay(y);return from[y];}
	void Link(int x,int y)
	{MakeRoot(x);fa[x]=y;Access(x);return;}
	void Cut(int x,int y)
	{MakeRoot(y);Access(x);Splay(x);fa[ls]=0;ls=0;PushUp(x);return;}
	#undef ls
	#undef rs
}LCT;
int Find(int x)
{return fa[x]==x?x:(fa[x]=Find(fa[x]));}
bool cMp(node x,node y)
{return x.a<y.a;}
int main()
{
	scanf("%d%d",&n,&m);
	ans=2147483647;
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=m;i++)
		scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].a,&a[i].b);
	sort(a+1,a+1+m,cMp);
	for(int i=1;i<=m;i++)
		val[i+n]=sum[i+n]=a[i].b,from[i+n]=i+n;
	for(int i=1;i<=m;i++){
		int Fa=Find(a[i].x),Fb=Find(a[i].y);
		bool line=1;
		if(Fa==Fb){
			int p=LCT.Split(a[i].x,a[i].y);
			if(sum[p]>a[i].b)
				LCT.Cut(a[p-n].x,p),LCT.Cut(a[p-n].y,p);
			else line=0;
		}
		else fa[Fa]=Fb;
		if(line) LCT.Link(a[i].x,i+n),LCT.Link(a[i].y,i+n);
		if(Find(1)==Find(n))
			ans=min(ans,a[i].a+sum[LCT.Split(1,n)]);
	}
	if(ans==2147483647) printf("-1");
	else printf("%d",ans);
}
发布了867 篇原创文章 · 获赞 55 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/103789575