题意:
给出一个n个点m条边的无向图,现在要从点1走到点n;
每条边有两个参数a和b,经过这条边必须分别要带不小于a和b的两种权值;
求携带的最小ab权值和,若无解输出-1;
2<=n<=50000,0<=m<=100000
题解:
挺神的一道题。。
考虑路径上最小的b的权值,只需要对b做一次最小生成树就可以了;
但是a的权值怎么办呢?
枚举!
枚举每次经过的最大的a权值,然后求b的最小生成树,更新答案;
但是为了保证最大,要按a权值升序排;
加边就是维护最小生成树啦,LCT!
正确性似乎不用太解释?
然后写一写调一调就好了;
我因为没判断弹的边和要加的边的大小关系WA了一发;
复杂度就是O(mlogm+mlogn)吧;
LCT最近刷到意识模糊。。。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 51000
#define which(x) (ch[fa[x]][1]==x)
using namespace std;
struct node
{
int x,y,a,b;
}eg[N<<1];
int fa[N*3],ch[N*3][2],val[N*3],ma[N*3];
bool rt[N*3],rev[N*3];
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
int cmp(node a,node b)
{
if(a.a==b.a)
return a.b<b.b;
return a.a<b.a;
}
void Pushup(int x)
{
ma[x]=val[x]>max(val[ma[ch[x][0]]],val[ma[ch[x][1]]])?x:
(val[ma[ch[x][0]]]>val[ma[ch[x][1]]]?ma[ch[x][0]]:ma[ch[x][1]]);
}
void reverse(int x)
{
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
void Pushdown(int x)
{
if(rev[x])
{
reverse(ch[x][0]);
reverse(ch[x][1]);
rev[x]=0;
}
}
void down(int x)
{
if(!rt[x]) down(fa[x]);
Pushdown(x);
}
void Rotate(int x)
{
int f=fa[x];
bool k=which(x);
if(rt[f]) rt[f]^=rt[x]^=1;
else ch[fa[f]][which(f)]=x;
ch[f][k]=ch[x][!k];
ch[x][!k]=f;
fa[ch[f][k]]=f;
fa[x]=fa[f];
fa[f]=x;
Pushup(f);
Pushup(x);
}
void Splay(int x)
{
down(x);
while(!rt[x])
{
int f=fa[x];
if(rt[f])
{
Rotate(x);
return ;
}
if(which(x)^which(f))
Rotate(x);
else
Rotate(f);
Rotate(x);
}
}
void access(int x)
{
int y=0;
while(x)
{
Splay(x);
rt[ch[x][1]]=1,rt[y]=0;
ch[x][1]=y;
Pushup(x);
y=x,x=fa[x];
}
}
void Mtr(int x)
{
access(x);
Splay(x);
reverse(x);
}
bool judge(int x,int y)
{
Mtr(x);
access(y);
Splay(x);
while(!rt[y])
y=fa[y];
return x==y;
}
void Link(int x,int y)
{
Mtr(x);
fa[x]=y;
}
void Cut(int t,int x,int y)
{
Mtr(t);
access(x);
Splay(t);
rt[ch[t][1]]=1;
fa[ch[t][1]]=0;
ch[t][1]=0;
access(y);
Splay(t);
rt[ch[t][1]]=1;
fa[ch[t][1]]=0;
ch[t][1]=0;
}
int main()
{
int n,m,i,j,k,x,y,ans;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
eg[i].x=read(),eg[i].y=read(),eg[i].a=read(),eg[i].b=read();
}
sort(eg+1,eg+1+m,cmp);
for(i=1;i<=n;i++)
rt[i]=1,ma[i]=i;
for(i=1,ans=0x3f3f3f3f;i<=m;i++)
{
x=eg[i].x,y=eg[i].y;
if(x==y) continue;
rt[i+n]=1,val[i+n]=eg[i].b,ma[i+n]=i+n;
if(judge(x,y))
{
if(val[ma[x]]>eg[i].b)
Cut(ma[x],x,y),Link(i+n,x),Link(i+n,y);
}
else
Link(i+n,x),Link(i+n,y);
if(judge(1,n))
ans=min(ans,eg[i].a+val[ma[1]]);
}
if(ans==0x3f3f3f3f)
puts("-1");
else
printf("%d\n",ans);
return 0;
}