题目大意:给一张图,但是有条边不能通过,但是只有到达那条边的端点之后才能知道这条边不能通过。求最坏情况下的最短路。
n
≤
1
0
5
,
m
≤
2
×
1
0
5
n\le10^5,m\le2\times 10^5
n≤105,m≤2×105
题解:
显然先求一个最短路树(到T的),那么只可能删树上的边(否则没有意义)。
因此设ans[s]表示答案,不难发现
a
n
s
[
x
]
=
m
a
x
(
m
i
n
(
a
n
s
[
y
]
+
w
(
x
,
y
)
)
,
g
[
x
]
)
ans[x]=max(min(ans[y]+w(x,y)),g[x])
ans[x]=max(min(ans[y]+w(x,y)),g[x]),其中
g
[
x
]
g[x]
g[x]表示删掉x的最短路树上的出边后,从x出发到T的最短路。
考虑非树边,不难发现从x出发(假设(x,fa[x])被删掉了),只有经过跨越被删掉的边的非树边才有意义(否则可以直接走树边),跨越之后直接沿着树边走到终点,代价是
d
T
(
u
)
−
d
T
(
x
)
+
w
e
i
g
h
t
(
u
,
v
)
+
d
T
(
v
)
dT(u)-dT(x)+weight(u,v)+dT(v)
dT(u)−dT(x)+weight(u,v)+dT(v),也就是每条非树边(u,v)只会对u到v的路径上除了LCA以外的点有
d
T
(
u
)
+
w
e
i
g
h
t
(
u
,
v
)
+
d
T
(
v
)
dT(u)+weight(u,v)+dT(v)
dT(u)+weight(u,v)+dT(v)的贡献,这些东西取min然后减掉dT(x)就是g[x]。
这个显然可以可并堆,但是懒所以场上写了启发式合并map。
map:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
typedef map<lint,int>::iterator mit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=100010,LOG=20,M=200010;const lint INF=LLONG_MAX/10;
struct edges{
int to,pre,w;
}e[M<<1];int h[N],etop,cs[M<<1];
inline int add_edge(int u,int v,int w) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop,e[etop].w=w; }
namespace dijkstra_space{
priority_queue<pair<lint,int> > q;int vis[N];
inline int dijkstra(int s,int n,lint *d)
{
rep(i,1,n) d[i]=INF,vis[i]=0;
while(!q.empty()) q.pop();
q.push(mp(d[s]=0,s));
while(!q.empty())
{
int x=q.top().sec;q.pop();
if(vis[x]) continue;vis[x]=1;
for(int i=h[x],y;i;i=e[i].pre)
if(d[y=e[i].to]>d[x]+e[i].w)
d[y]=d[x]+e[i].w,q.push(mp(-d[y],y));
}
return 0;
}
}using dijkstra_space::dijkstra;
namespace getg_space{
struct TR{
map<lint,int> c;
inline int ins(lint v) { return c[v]++; }
inline int del(lint v) { return c[v]--; }
inline int _merge(TR &t)
{
if(c.size()<t.c.size()) c.swap(t.c);
for(mit it=t.c.begin();it!=t.c.end();it++)
if(it->sec!=0) c[it->fir]+=it->sec;
map<lint,int>().swap(t.c);return 0;
}
inline int empty()
{
while(c.size()&&c.begin()->sec==0) c.erase(c.begin());
return c.size()==0;
}
inline lint top()
{
while(c.size()&&c.begin()->sec==0) c.erase(c.begin());
return c.size()==0?INF:c.begin()->fir;
}
}T[N];int dpt[N],fa[N],up[N][LOG],Log[N];vector<int> g[N];
inline int getup(int x)
{
dpt[x]=dpt[fa[x]]+1;
rep(i,1,Log[dpt[x]]) up[x][i]=up[up[x][i-1]][i-1];
Rep(i,g[x]) getup(g[x][i]);return 0;
}
inline int LCA(int x,int y)
{
if(dpt[x]<dpt[y]) swap(x,y);
for(int i=Log[dpt[x]];i>=0;i--)
if(up[x][i][dpt]>=y[dpt]) x=up[x][i];
if(x==y) return x;
for(int i=Log[dpt[x]];i>=0;i--)
if(up[x][i]^up[y][i]) x=up[x][i],y=up[y][i];
return up[x][0];
}
inline int dfs(int x,lint *f,lint *d)
{
int y;Rep(i,g[x]) dfs(y=g[x][i],f,d),T[x]._merge(T[y]);
f[x]=(T[x].empty()?INF:T[x].top()-d[x]);return 0;
}
inline int getg(int t,int n,lint *d,lint *f)
{
rep(x,1,n) if(x^t) for(int i=h[x],y;i;i=e[i].pre)
if(d[y=e[i].to]+e[i].w==d[x]) { fa[x]=y,cs[i]=cs[((i-1)^1)+1]=1;break; }
rep(x,1,n) up[x][0]=fa[x],(fa[x]?g[fa[x]].pb(x),0:0);
rep(i,2,n) Log[i]=Log[i>>1]+1;getup(t);
rep(x,1,n) for(int i=h[x];i;i=e[i].pre) if(!cs[i])
{
int y=e[i].to;cs[i]=cs[((i-1)^1)+1]=1;
lint v=d[x]+e[i].w+d[y];
T[x].ins(v),T[y].ins(v),
T[LCA(x,y)].del(v),T[LCA(x,y)].del(v);
}
dfs(t,f,d);return 0;
}
}using getg_space::getg;
lint ans[N],ds[N],dt[N],g[N];
namespace getans_space{
priority_queue<pair<lint,int> > q;int vis[N];
inline int getans(int s,int n,lint *g)
{
while(!q.empty()) q.pop();
rep(i,1,n) ans[i]=INF,vis[i]=0;
ans[s]=g[s];q.push(mp(-ans[s],s));
while(!q.empty())
{
int x=q.top().sec;q.pop();
if(vis[x]) continue;vis[x]=1;
ans[x]=max(ans[x],g[x]);
for(int i=h[x],y;i;i=e[i].pre)
if(ans[y=e[i].to]>max(ans[x]+e[i].w,g[e[i].to]))
ans[y]=max(ans[x]+e[i].w,g[y]),q.push(mp(-ans[y],y));
}
return 0;
}
}using getans_space::getans;
int main()
{
// freopen("data.in","r",stdin);
int n=inn(),m=inn(),s=inn(),t=inn(),u,v,w;
rep(i,1,m) u=inn(),v=inn(),w=inn(),add_edge(u,v,w),add_edge(v,u,w);
dijkstra(t,n,dt),getg(t,n,dt,g),g[t]=0,getans(t,n,g);
return !printf("%lld\n",ans[s]<INF?ans[s]:-1);
}
左偏树
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<utility>
#include<queue>
#define gc getchar()
#define N 210000
#define M 510000
#define S M<<1
#define lint long long
#define INF (LLONG_MAX/10-10)
#define mp make_pair
#define fir first
#define sec second
#define LOG 20
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef pair<lint,int> plii;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int dpt[N],u[M],v[M],w[M],up[N][LOG],Log[N];vector<pii> inse[N];
struct edges{
int to,pre,wgt,id;
}e[M<<1];int h[N],etop;plii val[S];int lc[S],rc[S],dist[S];
lint d[N];int node_cnt,del[S],vis[N],pre[N],fr[N],rt[N];
priority_queue<plii> q;vector<int> g[N];int used[M];lint f[N];
inline int add_edge(int u,int v,int w,int i,int x=0)
{ return e[x=++etop].to=v,e[x].pre=h[u],h[u]=etop,e[x].wgt=w,e[x].id=i; }
inline int dfs(int x,int fa=0)
{
dpt[x]=dpt[up[x][0]=fa]+1;
for(int i=1;i<=Log[dpt[x]];i++) up[x][i]=up[up[x][i-1]][i-1];
for(int i=0,y;i<(int)g[x].size();i++) if((y=g[x][i])^fa) dfs(y,x);
return 0;
}
inline int LCA(int x,int y)
{
if(dpt[x]<dpt[y]) swap(x,y);
for(int i=Log[dpt[x]];i>=0;i--)
if(dpt[up[x][i]]>=dpt[y]) x=up[x][i];
if(x==y) return x;
for(int i=Log[dpt[x]];i>=0;i--)
if(up[x][i]^up[y][i]) x=up[x][i],y=up[y][i];
return up[x][0];
}
inline int _merge(int x,int y)
{
if(!x||!y) return x+y;
if(val[x]>val[y]) swap(x,y);rc[x]=_merge(rc[x],y);
if(dist[lc[x]]<dist[rc[x]]) swap(lc[x],rc[x]);
if(rc[x]) dist[x]=dist[rc[x]]+1;else dist[x]=0;
return x;
}
inline int new_node(plii v) { return val[++node_cnt]=v,node_cnt; }
inline int ins(int &x,plii v) { return x=_merge(x,new_node(v)); }
inline int pop(int &x) { return x=_merge(lc[x],rc[x]); }
inline lint top(int &x) { while(x&&del[val[x].sec]) pop(x);return x?val[x].fir:INF; }
inline int fir_dijkstra(int s,int n,int m)
{
memset(vis,0,sizeof(int)*(n+1));
memset(pre,0,sizeof(int)*(n+1));
memset(fr,0,sizeof(int)*(n+1));
for(int i=1;i<=n;i++) d[i]=INF;
while(!q.empty()) q.pop();
q.push(mp(0,s)),d[s]=0;
while(!q.empty())
{
int x=q.top().sec;q.pop();
if(vis[x]) continue;vis[x]=1;
for(int i=h[x],y;i;i=e[i].pre)
if(!vis[y=e[i].to]&&d[e[i].to]>d[x]+e[i].wgt)
pre[y]=e[i].id,fr[y]=x,d[y]=d[x]+e[i].wgt,q.push(mp(-d[y],y));
}
for(int i=1;i<=n;i++) if(fr[i]) g[fr[i]].push_back(i);
for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;dfs(s);
for(int i=1;i<=n;i++) if(pre[i]) used[pre[i]]=1;
for(int i=1;i<=m;i++) if(!used[i])
inse[u[i]].push_back(mp(i,1)),
inse[v[i]].push_back(mp(i,1)),
inse[LCA(u[i],v[i])].push_back(mp(i,-1));
return 0;
}
inline int geth(int x)
{
for(int i=0,y;i<(int)g[x].size();i++)
geth(y=g[x][i]),rt[x]=_merge(rt[x],rt[y]);
for(int i=0,id;i<(int)inse[x].size();i++)
if(inse[x][i].sec>0) id=inse[x][i].fir,ins(rt[x],mp(d[u[id]]+d[v[id]]+w[id],id));
else del[inse[x][i].fir]=1;
return ((top(rt[x])<INF)?f[x]=top(rt[x])-d[x]:f[x]=INF),0;
}
inline int sec_dijkstra(int s,int n)
{
while(!q.empty()) q.pop();
memset(vis,0,sizeof(int)*(n+1));
for(int i=1;i<=n;i++) d[i]=INF;
q.push(mp(0,s)),d[s]=0;
while(!q.empty())
{
int x=q.top().sec;q.pop();
if(vis[x]) continue;vis[x]=1;
for(int i=h[x],y;i;i=e[i].pre)
{
if(vis[y=e[i].to]) continue;
if(max(f[y],d[x]+e[i].wgt)<d[y])
d[y]=max(f[y],d[x]+e[i].wgt),q.push(mp(-d[y],y));
}
}
return 0;
}
int main()
{
int n=inn(),m=inn(),s=inn(),t=inn();
for(int i=1;i<=m;i++) u[i]=inn(),v[i]=inn(),w[i]=inn(),
add_edge(u[i],v[i],w[i],i),add_edge(v[i],u[i],w[i],i);
fir_dijkstra(t,n,m);if(d[s]==INF) return printf("-1\n");
geth(t),f[t]=0;
for(int i=1;i<=n;i++) debug(i)sp,debug(f[i])ln;
sec_dijkstra(t,n);
return !printf("%lld\n",d[s]<INF?d[s]:-1);
}