path

题目链接

题意:给你一张有向加权图,n个节点,m条边,有Q次查询xi,输出图中,第xi小的路的权值。

思路:用vector<pi>保存每个点出度所连着的点和边权值,用一个改变优先级的优先队列保存:以u为终点,走过的路的权值和。对于Q次查询,我们找出最大的xi,记为mx,求出第1-第mx大的所有路径保存在ans中。如何求?取出优先队列的top(当前最短路径),枚举终点出度所连的信息,把新的路径长度(优先队列中的值 + 枚举的边权值)插入到multiset中。当set中元素个数等于mx时,还要继续枚举,直到set中最大的元素比当前路径长度小,原因请仔细思考。

#include <bits/stdc++.h>
#define pi pair<int,int>
#define mk make_pair
#define ll long long
using namespace std;
const int maxn = 5e4+10;

struct node {
    int u;
    ll dist;
    bool operator < (const node& t)const {
        return dist > t.dist;
    }
};
priority_queue<node>q;
vector<pi>G[maxn];
multiset<ll>s;
int qr[maxn];
ll ans[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,Q,u,v,w,mx = 0;
        scanf("%d%d%d",&n,&m,&Q);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            G[u].push_back(mk(w,v));
            q.push(node{v,w});
            s.insert(w);
        }

        for(int i=1;i<=n;i++)
            sort(G[i].begin(),G[i].end());

        for(int i=1;i<=Q;i++)
        {
            scanf("%d",&qr[i]);
            mx = max(qr[i],mx);
        }
        
        int cnt = 0;
        while(cnt < mx)
        {
            node tmp = q.top();
            q.pop();
            ans[++cnt] = tmp.dist;
            u = tmp.u;
            for(auto it : G[u])
            {
                v = it.second;
                ll ww = tmp.dist + it.first;
                if(s.size() == mx)
                {
                    auto p = --s.end();
                    if(*p <= ww)break;
                    s.erase(p);
                    s.insert(ww);
                }
                else s.insert(ww);
                q.push(node{v,ww});
            }
        }
        for(int i=1;i<=Q;i++)printf("%lld\n",ans[qr[i]]);

        s.clear();
        for(int i=1;i<=n;i++)G[i].clear();
        while(!q.empty())q.pop();
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值