题目地址:P5304 [GXOI/GZOI2019]旅行者

这里是官方题解

一个图 \(n\) 点 \(m\) 条边,里面有 \(k\) 个特殊点,问这 \(k\) 个点之间两两最短路的最小值是多少?
\(n \leq 10^5, m \leq 5 * 10 ^5\)

假设我们把特殊点分成 \(A,B\) 两个集合,新建 \(s\) 连 \(A\) 集合的所有点,边权 \(0\) ,新建 \(t\) 连接 \(B\) 集合里的所有点,边权 \(0\) ,那么 \(s\) 到 \(t\) 的最短路就是 \(A,B\) 集合点之间的最短路的最小值。

那么对于 \(k\) 个特殊点,我们枚举二进制里的第 \(i\) 位,把二进制第 \(i\) 位是 \(0\) 的点放在 \(A\) , \(1\) 的点放在 \(B\) ,用以上方法跑一个最短路。

然后跑 \(log\ n\) 次最短路之后,所有最短路的最小值就是最终答案。

原理是,假设 \(k\) 个特殊点里最近的是 \(x\) 和 \(y\) ,那么 \(x\) 和 \(y\) 一定有一个二进制位不一样,那么他们肯定在那次分组的时候被放进了不同的集合,从而肯定被算进了最后的答案之中最短路。

#include <bits/stdc++.h>

const int MAXN = 100010, MAXM = 700010;

struct Edge {
    int y, z;
    Edge *next;
}*a[MAXN], POOL[MAXM], *ptr, *back[MAXN];

void AddEdge(int x, int y, int z) {
    Edge *tmp = ptr++;
    tmp->y = y;
    tmp->z = z;
    tmp->next = a[x];
    a[x] = tmp;
}

int n, nodes[MAXN], k, s, t;
long long dis[MAXN];

long long dijkstra() {
    memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    std::priority_queue<std::pair<long long, int> > Q;
    Q.push(std::make_pair(0, s));
    for (int i = 1; i < n + 2; i++) {
        while (!Q.empty() && dis[Q.top().second] != -Q.top().first) Q.pop();
        if (Q.empty()) break;
        int now = Q.top().second;
        Q.pop();
        for (Edge *p = a[now]; p; p = p->next)
            if (dis[p->y] > dis[now] + p->z)
                Q.push(std::make_pair(-(dis[p->y] = dis[now] + p->z), p->y));
    }
    return dis[t];
}

int main(int argc, char* argv[]) {
    int T;
    scanf("%d", &T);
    while (T--) {
        ptr = POOL;
        memset(a, 0, sizeof a);
        int m;
        scanf("%d%d%d", &n, &m, &k);
        while (m--) {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            AddEdge(x, y, z);
        }
        for (int i = 1; i <= k; i++) scanf("%d", nodes + i);

        long long Ans = ~0ull>>1;
        s = n + 1, t = n + 2;
        for (int i = 0; (1 << i) <= k; i++) {
            Edge *backup = ptr;
            memcpy(back, a, (sizeof a[0]) * (n + 3));
            for (int j = 1; j <= k; j++) if (j & (1 << i)) {
                    AddEdge(s, nodes[j], 0);
                } else {
                    AddEdge(nodes[j], t, 0);
                }
            Ans = std::min(Ans, dijkstra());
            ptr = backup;
            memcpy(a, back, (sizeof a[0]) * (n + 3));
            for (int j = 1; j <= k; j++) if (j & (1 << i)) {
                    AddEdge(nodes[j], t, 0);
                } else {
                    AddEdge(s, nodes[j], 0);
                }
            Ans = std::min(Ans, dijkstra());
            ptr = backup;
            memcpy(a, back, (sizeof a[0]) * (n + 3));
        }
        printf("%lld\n", Ans);
    }
    return 0;
}

P5304 [GXOI/GZOI2019]旅行者的更多相关文章

  1. 洛谷 P5304 [GXOI/GZOI2019]旅行者(最短路)

    洛谷:传送门 bzoj:传送门 参考资料: [1]:https://xht37.blog.luogu.org/p5304-gxoigzoi2019-lv-xing-zhe [2]:http://www ...

  2. luogu P5304 [GXOI/GZOI2019]旅行者

    传送门 所以这个\(5s\)是SMG 暴力是枚举每一个点跑最短路,然后有一个很拿衣服幼稚的想法,就是把所有给出的关键点当出发点,都丢到队列里,求最短路的时候如果当前点\(x\)某个相邻的点\(y\)是 ...

  3. P5304 [GXOI/GZOI2019]旅行者(最短路/乱搞)

    luogu bzoj Orz自己想出神仙正解的sxy 描述略 直接把所有起点推进去跑dijkstra... 并且染色,就是记录到这个点的最短路是由哪个起点引导出来的 然后再把所有边反指跑一次... 之 ...

  4. 【题解】Luogu P5304 [GXOI/GZOI2019]旅行者

    原题传送门 题意:给你k个点,让你求两两最短路之间的最小值 我们考虑二进制拆分,使得每两个点都有机会分在不同的组\((A:0,B:1)\)中,从源点\(S\)向\(A/B\)中的点连边权为0的边,从\ ...

  5. [洛谷P5304][GXOI/GZOI2019]旅行者

    题目大意: 有一张 \(n(n\leqslant10^5)\) 个点 \(m(m\leqslant5\times10^5)\) 条边的有向有正权图,有$k(2\leqslant k\leqslant ...

  6. [LOJ3087][GXOI/GZOI2019]旅行者——堆优化dijkstra

    题目链接: [GXOI/GZOI2019]旅行者 我们考虑每条边的贡献,对每个点求出能到达它的最近的感兴趣的城市(设为$f[i]$,最短距离设为$a[i]$)和它能到达的离它最近的感兴趣的城市(设为$ ...

  7. 【BZOJ5506】[GXOI/GZOI2019]旅行者(最短路)

    [BZOJ5506][GXOI/GZOI2019]旅行者(最短路) 题面 BZOJ 洛谷 题解 正着做一遍\(dij\)求出最短路径以及从谁转移过来的,反过来做一遍,如果两个点不由同一个点转移过来就更 ...

  8. 洛谷 P 5 3 0 4 [GXOI/GZOI2019]旅行者

    题目描述 J 国有 n 座城市,这些城市之间通过 m 条单向道路相连,已知每条道路的长度. 一次,居住在 J 国的 Rainbow 邀请 Vani 来作客.不过,作为一名资深的旅行者,Vani 只对 ...

  9. BZOJ5506 GXOI/GZOI2019旅行者(最短路)

    本以为是个二进制分组傻逼题https://www.cnblogs.com/Gloid/p/9545753.html,实际上有神仙的一个log做法https://www.cnblogs.com/asul ...

随机推荐

  1. python icmp\dns\http监控网络各个节点状态,并记录日志

    配置文件如下:支持多节点: { "dns":[{"domainname":"www.baidu.com","dnsserver&q ...

  2. [kuangbin带你飞]专题二十二 区间DP-E-POJ - 1651

    区间DP模板题 做区间DP的题目的时候,我们考虑DP[i][j]的含义是什么? 由题意大概是这样的,我们可以从n个数中每次选一个我们以前没选过的数字拿走,需要消耗a[i]*a[i+1]*a[i-1]的 ...

  3. simpledet 的配置

    simpledet 的配置 1. 通过 docker 配置 simpledet 1.1 系统要求 ubuntu16.04 python >=3.5 1.2 下载 docker 镜像 匹配的版本为 ...

  4. 详解WTL应用向导

    之前向 VS2019 中添加了 WTL 应用向导,今天来分析下该应用向导安装的相关文件,最终达到拷贝相关文件到 VS2019 的相应目录中即可直接使用 WTL 应用向导的目的. 在 VS2017 之前 ...

  5. Docker 核心技术之网络管理

    为什么需要Docker网络管理 容器的网络默认与宿主机.与其他容器都是相互隔离. 容器中可以运行一些网络应用(如nginx.web应用.数据库等),如果要让外部也可以访问这些容器内运行的网络应用,那么 ...

  6. python中的技巧——杂记

    杂记 zip的用法 对于 a = [1,2,3] b = [3,2,1] 若要同时遍历 for x, y in zip(a, b): pass zip(a, b)=> [(1,2,3),(3,2 ...

  7. 自动化测试框架【windows版】:JMeter + Ant + Jenkins

    前提条件:windows安装了jmeter.ant.jenkins 安装方法参考汇总目录中对应的博文 截图看不清的,可以调大浏览器倍数看 jenkins驱动ant执行,ant驱动jmeter执行 an ...

  8. 【优秀的iPhone/iPad数据恢复工具】Omni Recover for Mac 2.5

    [简介] 今天和大家分享最新的 Omni Recover for Mac 2.5 版本,这是一款Mac上优秀的iPhone/iPad设备数据恢复工具,支持恢复误删除的短信.照片.视频.文档.通话记录等 ...

  9. 【深度学习】RNN | GRU | LSTM

    目录: 1.RNN 2.GRU 3.LSTM 一.RNN 1.RNN结构图如下所示: 其中: $a^{(t)} = \boldsymbol{W}h^{t-1} + \boldsymbol{W}_{e} ...

  10. 路径分隔符不一致,导致windows下不能开发

    最近想要基于YAPI扩展开发一个自己的API管理平台,但是发现在windows下直接跑会报错,在Mac跑就没事 报的错是: Uncaught TypeError: $export is not a f ...