【图论】K短路(可并堆)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/86542992

分析:

反向建一颗最短路树(即根节点时目标节点)

每条非最短路径,一定可以表示为一些非树边的有序集合。

然后可以通过依次拓展的方式,来得到第K大。

每次拓展有两种方式(假设最后一条非树边为[u,v]):
1、把最后一条边替换为:从u到根的路径上,比其大的最小的非树边。
2、把v到根的路径上最小的一条非树边加在序列最后。

实现可以用可持久化可并堆完成。

例题:HDU5960

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define SF scanf
#define PF printf
#define MAXN 400010
#define INF 1e15
using namespace std;
typedef long long ll;
int s,t;
vector<int> a[MAXN],b[MAXN],wa[MAXN],wb[MAXN];
int fa[MAXN];
int st[MAXN],d[MAXN];
ll dis[MAXN];
struct node *NIL;
struct node{
	ll val;
	int dis,to;
	node *ch[2];	
}Tree[MAXN*40];
node *ncnt=Tree,*rt[MAXN];
node *Newnode(int to,int val){
	ncnt++;
	ncnt->to=to,ncnt->val=val;
	ncnt->ch[0]=ncnt->ch[1]=NIL;
	ncnt->dis=0;
	return ncnt;
}
void add_edge(int x,int y,int val){
	a[x].push_back(y);
	b[y].push_back(x);
	wa[x].push_back(val);
	wb[y].push_back(val);
	d[x]++;
}
int n,k;
void init(){
	NIL=Tree;
	NIL->ch[0]=NIL->ch[1]=NIL;	
	s=n+1,t=3*n+1;
	int c0,c1,co;
	ncnt=NIL;
	for(int i=1;i<=t;i++){
		dis[i]=INF;
		a[i].clear();
		b[i].clear();
		wa[i].clear();
		wb[i].clear();
	}
	for(int i=1;i<=n;i++){
		SF("%d%d%d",&c0,&c1,&co);
		add_edge(n+i,i,-c0);
		add_edge(2*n+i,i,-c1);
		if(i!=n){
			add_edge(n+i,n+i+1,0);
			add_edge(2*n+i,2*n+i+1,0);
			if(co)
				add_edge(i,2*n+i+1,0);
			else
				add_edge(i,n+i+1,0);
		}
		else
			add_edge(n,t,0),add_edge(2*n,t,0),add_edge(3*n,t,0);
	}
}
void prepare(){
	int top=1;
	st[top]=t;
	dis[t]=fa[t]=0;
	while(top){
		int x=st[top--];
		for(int i=0;i<int(b[x].size());i++){
			int u=b[x][i];
			if(dis[u]>dis[x]+wb[x][i]){
				dis[u]=dis[x]+wb[x][i];
				fa[u]=x;
			}
			d[u]--;
			if(d[u]==0)
				st[++top]=u;
		}
	}
}
int tot;
node *merge(node *x,node *y){
	if(x==NIL) return y;
	if(y==NIL) return x;
	if(x->val > y->val)
		swap(x,y);
	node *nx=++ncnt;
	*nx=*x;
	nx->ch[1]=merge(nx->ch[1],y);
	if(nx->ch[1]->dis > nx->ch[0]->dis)
		swap(nx->ch[1],nx->ch[0]);
	nx->dis=nx->ch[1]->dis+1;
	return nx;
}
void dfs(int x){
	rt[x]=rt[fa[x]];
	for(int i=0;i<int(a[x].size());i++)
		if(a[x][i]!=fa[x])
			rt[x]=merge(Newnode(a[x][i],dis[a[x][i]]-dis[x]+wa[x][i]),rt[x]);
	for(int i=0;i<int(b[x].size());i++)
		if(fa[b[x][i]]==x)
			dfs(b[x][i]);
}
priority_queue<pair<ll,node *>,vector<pair<ll,node *> >,greater<pair<ll,node *> > >q;
int main(){
	int Cas;
	SF("%d",&Cas);
	while(Cas--){
		SF("%d%d",&n,&k);
		k--;
		init();
		prepare();
		rt[0]=NIL;
		dfs(t);
		if(k==0){
			PF("%lld\n",-dis[s]);
			continue;	
		}
		if(rt[s]!=NIL)
			q.push(make_pair(dis[s]+rt[s]->val,rt[s]));
		while(--k&&q.size()){
			node *x=q.top().second;
			ll val=q.top().first;
			q.pop();
			int v=x->to;
			if(rt[v]!=NIL)
				q.push(make_pair(val+rt[v]->val,rt[v]));
			if(x->ch[0]!=NIL)
				q.push(make_pair(val- x->val + x->ch[0]->val,x->ch[0]));
			if(x->ch[1]!=NIL)
				q.push(make_pair(val- x->val + x->ch[1]->val,x->ch[1]));
		}
		if(q.empty())
			PF("-1\n");
		else
			PF("%lld\n",-q.top().first);
		while(!q.empty())
			q.pop();
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/86542992