题目大意: 有一张图,每条边有两个属性 a i a_i ai 和 b i b_i bi,对于 1 1 1 到 n n n 的一条路径,它的花费是路径上所有边的 max { a i } + max { b i } \max\{a_i\}+\max\{b_i\} max{ai}+max{bi},问花费最小的路径的花费是?
题解
有两个属性的话不好处理,我们将一个属性 a i a_i ai 排序,然后将边一条一条加进来,用 L C T LCT LCT 去维护,假如加进来的边连接的两点已经连通了,那么看一下这两点间路径上 b i b_i bi 最大的那条边,假如我加进来的这条边的 b i b_i bi 比他小,那么就把他删掉,然后把这条边加进来。
每次加边后,此时的 max { a i } \max\{a_i\} max{ai} 就等于我加进来的这条边的 a i a_i ai,然后 max { b i } \max\{b_i\} max{bi} L C T LCT LCT 已经帮我维护好了。
但是要知道 L C T LCT LCT 这个家伙,是会改变树的形态的,也就是说,边的信息存不了,所以对于每条边我们开一个新的点去存他的信息,然后让这个点去和它连接的两点连接。
判断两点是否连通我用了并查集,比 L C T LCT LCT 要快一丢丢。
代码如下:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 200010
struct node{
node *zuo,*you,*fa,*maxb;
int x,lazy,edge;
node(int c,int e):zuo(NULL),you(NULL),fa(NULL),x(c),maxb(this),lazy(0),edge(e){};
void update()
{
maxb=this;
if(zuo!=NULL&&zuo->maxb->x>maxb->x)maxb=zuo->maxb;
if(you!=NULL&&you->maxb->x>maxb->x)maxb=you->maxb;
}
bool notroot(){return fa!=NULL&&(fa->zuo==this||fa->you==this);}
void pushdown()
{
if(lazy==1)
{
node *tt=zuo;zuo=you;you=tt;
if(zuo!=NULL)zuo->lazy^=1;
if(you!=NULL)you->lazy^=1;
lazy=0;
}
}
void pushr()
{
lazy^=1;
pushdown();
}
};
node *a[maxn];
int n,m;
struct ro{int x,y,a,b;};
ro road[maxn];
bool cmp(ro x,ro y){return x.a<y.a;}
int f[maxn];
int ans=2e9;
int zhaobaba(int x){return x==f[x]?x:f[x]=zhaobaba(f[x]);}
inline int minn(int x,int y){return x<y?x:y;}
node *zhan[maxn];
int t=0;
void splay(node *x)
{
node *p=x;
while(p!=NULL)zhan[++t]=p,p=p->fa;
while(t>0)zhan[t--]->pushdown();
while(x->notroot())
{
node *fa=x->fa,*gfa=fa->fa;
if(fa->zuo==x)
{
fa->zuo=x->you;
if(x->you!=NULL)x->you->fa=fa;
x->you=fa;
}
else
{
fa->you=x->zuo;
if(x->zuo!=NULL)x->zuo->fa=fa;
x->zuo=fa;
}
fa->fa=x;x->fa=gfa;
if(gfa!=NULL)
{
if(gfa->zuo==fa)gfa->zuo=x;
if(gfa->you==fa)gfa->you=x;
}
fa->update();x->update();
}
}
void access(node *x)
{
for(node *y=NULL;x!=NULL;y=x,x=x->fa)
splay(x),x->you=y,x->update();
}
void makeroot(node *x)
{
access(x);splay(x);
x->pushr();
}
void split(node *x,node *y)
{
makeroot(x);access(y);
splay(y);
}
void link(node *x,node *y)
{
makeroot(x);
x->fa=y;
}
void del(node *x,node *y)
{
makeroot(x);access(y);splay(y);
x->fa=y->zuo=NULL;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d %d %d %d",&road[i].x,&road[i].y,&road[i].a,&road[i].b);
sort(road+1,road+m+1,cmp);
for(int i=1;i<=n;i++)
a[i]=new node(0,-1);
for(int i=n+1;i<=n+m;i++)
a[i]=new node(road[i-n].b,i-n);
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=m;i++)
{
int x=road[i].x,y=road[i].y;
if(zhaobaba(x)==zhaobaba(y))
{
split(a[x],a[y]);
if(road[i].b<a[y]->maxb->x)
{
node *p=a[y]->maxb;
del(p,a[road[p->edge].x]);del(p,a[road[p->edge].y]);
link(a[x],a[i+n]);link(a[y],a[i+n]);
}
}
else link(a[x],a[i+n]),link(a[y],a[i+n]),f[zhaobaba(y)]=zhaobaba(x);
if(zhaobaba(1)==zhaobaba(n))split(a[1],a[n]),ans=minn(ans,road[i].a+a[n]->maxb->x);
}
if(ans<2e9)printf("%d",ans);
else printf("-1");
}