题意:给你有向图,每次查询第k长的路径,而且这里面环状路径可以无限走。
解:被次大最短路,或者第k大最短路的思想所限制了,题解的思路就很简单了,被按在地上摩擦,就是用优先队列按照距离从小到大排序,把一个点取出时,可能加进去的答案就是当前这个节点连出去的边最短的那一条(点出去的边也需要排序),或者上一个节点还可以延展出去的路径。在将查询排序一下,就可以了。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn=5e4+5;
struct node {
ll to,w;
bool operator < (const node &p) const {
return w<p.w;
}
};
vector<node> mp[maxn];
struct P {
ll pdist,pre,id,ndist,np;
bool operator < (const P &p) const {
return ndist>p.ndist;
}
};
priority_queue<P> q;
struct PP {
int id,k;
bool operator < (const PP &p) const {
return k<p.k;
}
} qu[maxn];
int T,n,m,qnum,ans[maxn];
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&n,&m,&qnum);
for(int i=1; i<=n; ++i) mp[i].clear();
while(!q.empty()) q.pop();
ll u,v,w,k;
for(int i=1; i<=m; ++i) {
scanf("%lld%lld%lld",&u,&v,&w);
mp[u].push_back(node {v,w});
q.push(P {0,-1,0,w,v});
}
for(int i=1; i<=n; ++i) {
sort(mp[i].begin(),mp[i].end());
}
for(int i=1; i<=qnum; ++i) {
scanf("%lld",&k);
qu[i]=PP {i,k};
}
sort(qu+1,qu+qnum+1);
ll pdist,pre,id,ndist,np,cnt=1,qid=1;
P top;
while(1) {
top=q.top(),q.pop();
while(cnt == qu[qid].k && qid<=qnum) {
ans[qu[qid].id]=top.ndist;
qid++;
}
if(qid==qnum+1) break;
cnt++,k--;
pdist=top.pdist,pre=top.pre;
id=top.id,ndist=top.ndist,np=top.np;
// cout<<pdist<<" "<<pre<<" "<<id<<" "<<ndist<<" "<<np<<endl;
if(pre!=-1 && id<(int)mp[pre].size()) {
q.push(P {pdist,pre,id+1,pdist+mp[pre][id].w,mp[pre][id].to});
}
if((int)mp[np].size()) q.push(P {ndist,np,1,ndist+mp[np][0].w,mp[np][0].to});
}
for(int i=1; i<=qnum; ++i) printf("%lld\n",ans[i]);
}
return 0;
}