Description:
给定一个无向连通图,每条边有两个属性,(a_i,b_i),找一条从1号点到n号点的路径,使路径上的 ({max}a_{i}+maxb_{i}) 最小
Hint:
(n=5*10^4,m<=10^5)
Solution:
一看到题目就想到最短路,然后发现行不通
最短路行不通,那就考虑最小生成树
一个属性显然可以直接做
但是现在有两个属性
考虑按边权枚举其中一个属性
即按 (ai) 排序后每次向图中加入一条边
同时维护以 (bi) 为边权的最小生成树
若成环,选择一条 (bi) 较小的边
每次加边后更新1到n的答案
维护最小生成树用 (lct) 解决
#include<bits/stdc++.h>
using namespace std;
const int mxn=1e6+5,inf=1e9;
struct ed {
int u,v,w,z,id;
}q[mxn];
int n,m,tot,mx[mxn],fa[mxn],ch[mxn][2],rev[mxn],st[mxn],val[mxn];
pair<int ,int > g[mxn];
map<pair<int ,int >,int > s;
int cmp(ed x,ed y) {
return x.w<y.w;
}
inline void checkmi(int &x,int y,int z) {
if(x>y+z) x=y+z;
}
namespace lct {
int isnotrt(int x) {
return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
void push_up(int x) {
mx[x]=x;
if(val[mx[x]]<val[mx[ch[x][0]]]) mx[x]=mx[ch[x][0]];
if(val[mx[x]]<val[mx[ch[x][1]]]) mx[x]=mx[ch[x][1]];
}
void push_down(int x) {
if(rev[x]) {
swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
rev[ch[x][0]]^=1; rev[ch[x][1]]^=1; rev[x]=0;
}
}
void rotate(int x) {
int y=fa[x],z=fa[y],tp=ch[y][1]==x;
if(isnotrt(y)) ch[z][ch[z][1]==y]=x; fa[x]=z;
ch[y][tp]=ch[x][tp^1],fa[ch[x][tp^1]]=y;
ch[x][tp^1]=y; fa[y]=x;
push_up(y),push_up(x);
}
void splay(int x) {
int tp=x,s=0; st[++s]=tp;
while(isnotrt(tp)) st[++s]=tp=fa[tp];
while(s) push_down(st[s]),--s;
while(isnotrt(x)) {
int y=fa[x],z=fa[y];
if(isnotrt(y))
(ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
rotate(x);
}
}
void access(int x) {
for(int y=0;x;x=fa[y=x])
splay(x),ch[x][1]=y,push_up(x);
}
void makert(int x) {
access(x); splay(x);
swap(ch[x][0],ch[x][1]); rev[x]^=1;
}
int findrt(int x) {
access(x); splay(x);
while(ch[x][0]) push_down(x),x=ch[x][0];
splay(x); return x;
}
void link(int x,int y) {
makert(x); fa[x]=y;
}
void cut(int x,int y) {
makert(x); access(y); splay(y);
fa[x]=ch[y][0]=0; push_up(y);//
}
int query(int x,int y) {
makert(x); access(y); splay(y);
return mx[y];
}
}
using namespace lct;
int main()
{
scanf("%d%d",&n,&m); tot=n; int ans=inf;
for(int i=1;i<=m;++i) {
scanf("%d%d%d%d",&q[i].u,&q[i].v,&q[i].w,&q[i].z);
s[make_pair(q[i].u,q[i].v)]=s[make_pair(q[i].v,q[i].u)]=++tot;
val[tot]=q[i].z; g[tot]=make_pair(q[i].u,q[i].v);
}
sort(q+1,q+m+1,cmp);
for(int i=1;i<=m;++i) {
int u=q[i].u,v=q[i].v,w=s[make_pair(u,v)];
if(findrt(u)!=findrt(v))
link(u,w),link(w,v),mx[w]=w,val[w]=q[i].z;
else {
int tp=query(u,v);
if(val[tp]>q[i].z) {
cut(g[tp].first,tp);
cut(g[tp].second,tp);
link(u,w); link(v,w);
mx[w]=w,val[w]=q[i].z;
}
}
if(findrt(1)==findrt(n)) checkmi(ans,val[query(1,n)],q[i].w);
}
printf("%d",ans==inf?-1:ans);
}