您的位置:首页 > 其它

【NOI2014】魔法森林

2016-09-05 20:18 232 查看

Description

给出一张n个点,m条边的图,每条边有两个边权(a,b),求从1到n的路径中所有的权a最大值+权b最大值的最小值是多少。

n<=50000,m<=100000

Solution

长得那么像双关键字的最小生成树。

不过是最大值的和而已。

那么我们可以把所有的边按a值从小到大排序。

然后依次加边,如果形成了环那么就删去环上b值最大的边。

原因嘛参照kurskal的证明~

我才不会说我不会证

也就是说我们要动态加边,删边,求最大值。

LCT嘛。。。

话说各位说用LCT神犇好像都是用spfa虐过去的啊

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 150005
using namespace std;
struct note{int x,y,a,b;}a
;
bool cmp(note x,note y) {return x.a<y.a;}
int t
[2],f
,p
,mx
,key
,d
,rev
;
int n,m,ans,fa
;
int get(int x) {return fa[x]?fa[x]=get(fa[x]):x;}
int son(int x) {
return t[f[x]][1]==x;
}
void updata(int x) {
int l=t[x][0],r=t[x][1];
if (a[mx[l]].b>a[mx[r]].b) mx[x]=mx[l];
else mx[x]=mx[r];
if (a[key[x]].b>a[mx[x]].b) mx[x]=key[x];
}
void down(int x) {
if (rev[x]) {
rev[x]=0;
if (t[x][0]) rev[t[x][0]]^=1;
if (t[x][1]) rev[t[x][1]]^=1;
swap(t[x][0],t[x][1]);
}
}
int remove(int x,int y) {
do {
d[++d[0]]=x;x=f[x];
} while (x!=y);
while (d[0]) down(d[d[0]--]);
}
void rotate(int x) {
int y=f[x],z=son(x);f[x]=f[y];
if (f[x]) t[f[x]][son(y)]=x;
else p[x]=p[y],p[y]=0;
if (t[x][1-z]) f[t[x][1-z]]=y;
f[y]=x;t[y][z]=t[x][1-z];t[x][1-z]=y;
updata(y);updata(x);
}
void splay(int x,int y) {
remove(x,y);
while (f[x]!=y) {
if (f[f[x]]!=y)
if (son(x)==son(f[x])) rotate(f[x]);
else rotate(x);
rotate(x);
}
}
void access(int x) {
int y=0;
while (x) {
splay(x,0);
f[t[x][1]]=0;p[t[x][1]]=x;
t[x][1]=y;p[y]=0;f[y]=x;
updata(x);y=x;x=p[x];
}
}
void makeroot(int x) {
access(x);splay(x,0);rev[x]^=1;
}
void link(int x,int y) {
makeroot(x);p[x]=y;
}
void cut(int x,int y) {
makeroot(x);access(y);splay(y,0);
t[y][0]=0;p[x]=f[x]=0;
updata(y);
}
int find(int x,int y) {
makeroot(x);access(y);splay(y,0);
return mx[y];
}
int main() {
scanf("%d%d",&n,&m);
fo(i,1,m) scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].a,&a[i].b),key[i+n]=i;
sort(a+1,a+m+1,cmp);ans=0x7fffffff;
fo(i,1,m) {
if (a[i].x==a[i].y) continue;
int ax=get(a[i].x),by=get(a[i].y);
if (ax==by) {
int l=find(a[i].x,a[i].y);
if (a[l].b>a[i].b) {
cut(a[l].x,l+n);cut(a[l].y,l+n);
link(a[i].x,i+n);link(a[i].y,i+n);
}
} else {
fa[by]=ax;
link(a[i].x,i+n);link(a[i].y,i+n);
}
ax=get(1);by=get(n);
if (ax==by) ans=min(ans,a[i].a+a[find(1,n)].b);
}
if (ans==0x7fffffff) printf("-1");else printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: