链接:HDU6705 - path
给出一个带边权有向图,含有 n n n个结点 m m m条边,共 q q q次询问,每次询问在所有路径中第 k k k小的路径边权和是多少?(一条边可以走无限次)
每次 把边权和尽量小的路径状态 放入优先队列中,每次从队首取出当前最小路径(即第 i i i小),利用此路径状态 找到接下来尽量小的路径状态。
先将所有结点的 出边按照边权从小到大排序,将所有点 最小出边 放入优先队列中。
假设一条路径是 以 u → v u\rarr v u→v结尾,其 路径和为 s u m sum sum,且 u → v u\rarr v u→v是 u u u的所有出边中边权第 c u r cur cur小 的,该路径下一条可能的尽量小路径有 2 2 2种情况:
所以需要记录的路径状态有: u , v , c u r , s u m u,v,cur,sum u,v,cur,sum。
#include
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=5e5+50;
int n,m,q;
LL ans[maxn];
struct edge
{
int to;
LL w;
};
vector<edge> g[maxn];
bool cmp(const edge &x,const edge &y)
{
return x.w<y.w;
}
struct node
{
int u,v;
int cur;
LL sum;
friend bool operator < (const node &x,const node &y)
{
return x.sum>y.sum;
}
};
void init()
{
for(int i=1;i<=n;i++)
g[i].clear();
}
void solve()
{
for(int i=1;i<=n;i++)
sort(g[i].begin(),g[i].end(),cmp);
priority_queue<node> q;
for(int i=1;i<=n;i++)
{
if(!g[i].empty())
q.push(node{
i,g[i][0].to,0,g[i][0].w});
}
for(int i=1;i<=50000;i++)
{
int u=q.top().u,v=q.top().v,cur=q.top().cur;
LL sum=q.top().sum;
q.pop();
ans[i]=sum;
if(!g[v].empty())
q.push(node{
v,g[v][0].to,0,sum+g[v][0].w});
if(cur+1<g[u].size())
q.push(node{
u,g[u][cur+1].to,cur+1,sum-g[u][cur].w+g[u][cur+1].w});
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d %d",&n,&m,&q);
init();
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
g[u].push_back(edge{
v,w});
}
solve();
while(q--)
{
int k;
scanf("%d",&k);
printf("%lld\n",ans[k]);
}
}
return 0;
}