家访 - 最短路 - 启发式合并 - 可并堆

题目大意:给一张图,但是有条边不能通过,但是只有到达那条边的端点之后才能知道这条边不能通过。求最坏情况下的最短路。 n ≤ 1 0 5 , m ≤ 2 × 1 0 5 n\le10^5,m\le2\times 10^5 n105,m2×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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值