这一题是 L C T LCT LCT(当然,思路是类似的,可以类比一下,有时间再打),大雾…
https://www.luogu.org/problemnew/show/P2387
n n n个点, m m m条边,每条边有两个权值 z 1 , z 2 z_1,z_2 z1,z2,现在让你找到两个值使得它们分别大于从 1 1 1到 n n n的某一条路径上的两个值,要求这两个值的最小总和。
考虑最短路。
显然最短路无法维护两个值,不妨使得某一个值 z 1 z_1 z1有序(升序),然后根据第二个值做决策。
那么,当每加入一条新边的时候,它就可能会更新答案,不妨在这时跑边两边的两个点的最短路找到在此时最小的 z 2 z_2 z2,然后 n o w z 1 + m i n { z 2 } nowz_1+min\{z_2\} nowz1+min{z2}就是此时的最小答案。
正确性很容易显然,很容易 yy \text y\text y yy。
当然,必须要采用动态加点的堆优化+ s p f a / d i j k s t r a spfa/dijkstra spfa/dijkstra,其实我一直分不清这两个的区别,打法类似,所以不知道我的代码是哪一种,欢迎大佬指正。
时间复杂度: Θ ( 玄 学 ) \Theta(玄学) Θ(玄学)。
#include
#include
#include
#include
using namespace std;
struct node3
{
int id,d;
friend bool operator <(node3 x,node3 y)
{
return x.d>y.d;
}
};
priority_queue<node3> f;
int n,m,len=0,ans=2147483647;
struct node1{int x,y,z1,z2;} d[100010];
struct node2{int x,y,z,next;} a[200010];
int last[50010],dis[50010];
bool bz[50010];
bool cmp(node1 x,node1 y)
{
return x.z1<y.z1;
}
void ins(int x,int y,int z)
{
a[++len]=(node2){x,y,z,last[x]}; last[x]=len;
}
int dijkstra(int st1,int st2)
{
f.push((node3){st1,dis[st1]});
f.push((node3){st2,dis[st2]});
while(!f.empty())
{
int x=f.top().id;
f.pop();
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(dis[y]>max(dis[x],a[i].z))
{
dis[y]=max(dis[x],a[i].z);
if(!bz[y]) f.push((node3){y,dis[y]}),bz[y]=true;
}
}
bz[x]=false;
}
return dis[n];
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d %d %d %d",&d[i].x,&d[i].y,&d[i].z1,&d[i].z2);
sort(d+1,d+m+1,cmp);
memset(dis,63,sizeof(dis));
dis[1]=0;
bool flag=false;
for(int i=1;i<=m;i++)
{
if(d[i].z1>=ans) break;
if(d[i].x==d[i].y) continue;
ins(d[i].x,d[i].y,d[i].z2);
ins(d[i].y,d[i].x,d[i].z2);
if(d[i].x==1||d[i].y==1) flag=true;
if(flag) ans=min(ans,d[i].z1+dijkstra(d[i].x,d[i].y));
}
printf("%d",ans<(int)1e9?ans:-1);
}
L C T LCT LCT维护最小生成树的思想。
类似的,我们按照 z 1 z_1 z1排序,在 L C T LCT LCT中维护 z 2 z_2 z2的值,然后就可以将时间复杂度稳定在 Θ ( n l o g n ) \Theta(nlogn) Θ(nlogn)。
#include
#include
#include
using namespace std;
struct node1{int d,fa,ma,pos,lazy,son[2];} tr[300010];
struct node2{int x,y,z1,z2;} a[300010],d[300010];
int n,m,ans=2147483647;
bool cmp(node2 x,node2 y)
{
return x.z1<y.z1;
}
bool isroot(int x)
{
return tr[tr[x].fa].son[0]!=x&&tr[tr[x].fa].son[1]!=x;
}
bool isson(int x)
{
return x==tr[tr[x].fa].son[1];
}
void change(int x)
{
if(!x)return;
swap(tr[x].son[0],tr[x].son[1]);
tr[x].lazy^=1;
}
void pushup(int x)
{
int lc=tr[x].son[0],rc=tr[x].son[1];
tr[x].ma=tr[x].d,tr[x].pos=x;
if(tr[lc].ma>tr[x].ma) tr[x].ma=tr[lc].ma,tr[x].pos=tr[lc].pos;
if(tr[rc].ma>tr[x].ma) tr[x].ma=tr[rc].ma,tr[x].pos=tr[rc].pos;
}
void pushdown(int x)
{
if(!tr[x].lazy) return;
change(tr[x].son[0]),change(tr[x].son[1]);
tr[x].lazy=0;
}
void rot(int x)
{
int w=isson(x),y=tr[x].fa,yy=tr[y].fa;
tr[y].son[w]=tr[x].son[w^1];
if(tr[y].son[w]) tr[tr[y].son[w]].fa=y;
tr[x].fa=yy;
if(!isroot(y)) tr[yy].son[isson(y)]=x;
tr[x].son[w^1]=y;tr[y].fa=x;
pushup(y);
}
int sta[300010];
int top;
void splay(int x)
{
sta[top=1]=x;
for(int i=x;!isroot(i);i=tr[i].fa)
sta[++top]=tr[i].fa;
while(top) pushdown(sta[top--]);
for(int y=tr[x].fa;!isroot(x);rot(x),y=tr[x].fa)
if(!isroot(y)) isson(x)^isson(y)?rot(x):rot(y);
pushup(x);
}
void access(int x)
{
for(int y=0;x;y=x,x=tr[x].fa)
splay(x),tr[x].son[1]=y,pushup(x);
}
int findroot(int x)
{
access(x);splay(x);
while(tr[x].son[0]) x=tr[x].son[0];
//splay(x);
return x;
}
void makeroot(int x)
{
access(x);splay(x);change(x);
}
void link(int x,int y)
{
makeroot(x);
if(findroot(y)!=x) tr[x].fa=y;
}
void split(int x,int y)
{
makeroot(x);access(y);splay(y);
}
void del(int x,int y)
{
split(x,y);
tr[x].fa=tr[y].son[0]=0,pushup(x),pushup(y);
}
int query(int x,int y)
{
split(x,y);
return tr[y].pos;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d %d %d %d",&d[i].x,&d[i].y,&d[i].z1,&d[i].z2);
sort(d+1,d+m+1,cmp);
for(int i=n+1;i<=n+m;i++)
a[i]=d[i-n];
for(int i=0;i<=(n<<1);i++)
tr[i]=(node1){0,0,0,i,0,0,0};
for(int i=n+1;i<=n+m;i++)
{
if(findroot(a[i].x)!=findroot(a[i].y))
{
tr[i].d=a[i].z2;
link(a[i].x,i);link(a[i].y,i);
}
else
{
int pos=query(a[i].x,a[i].y);
if(pos>n&&a[i].z2<a[pos].z2)
{
del(a[pos].x,pos);del(a[pos].y,pos);
tr[i].d=a[i].z2;
link(a[i].x,i);link(a[i].y,i);
}
}
if(findroot(1)==findroot(n)) ans=min(ans,a[i].z1+a[query(1,n)].z2);
}
printf("%d",findroot(1)==findroot(n)?ans:-1);
}