Luogu · 传送门

Orz THU众大佬,lct(注意不是link-cut-tree,是一个大佬)


这道题很容易让人联想到 最短路,但是最短路需要先 建图

暴力建出所有边的算法显然是不可行的,因为这样会建出 \(O(n^2 + m)\) 条边;

那么我们要考虑能不能 减少一些边 ,使边的数量可以接受。

从哪里入手减少边的数量呢?异或或许是一个不错的切入口。

举个栗子:

假设我们要从 \(001_2\) 到 \(010_2\),我们要花费 \(2^0 + 2^1\) 的费用;

但是,最短路有一个 优越的性质,我们可以把边拆开来,可以先从 \(001_2\) 到 \(000_2\),再从 \(000_2\) 到 \(010_2\),费用是一样的

这样我们对于每个点 \(i\),只需要建 \(i\) 到 \(i \ XOR \ 2^k\) 的边,之后 Dijkstra 就可以了哈。

需要注意的是 边界情况:从 \(i\) 到 \(j\) 经过的中间点可能超过 \(n\),对此有 2 种处理方法:

  1. 建边和 Dijkstra 的范围调整为 \([0,n]\)
  2. 建边和 Dijkstra 的范围调整为 \([1, 2^k-1],k = min \{ k \ | \ n \leq 2^k -1 \}\)

方法 1 的代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
 
const int maxn = 100007;
const int maxm = 2500007;
int n, m, c;
int edgenum, head[maxn], nxt[maxm], vet[maxm], val[maxm];
inline void addedge(int u, int v, int w){
    ++edgenum;
    vet[edgenum] = v;
    val[edgenum] = w;
    nxt[edgenum] = head[u];
    head[u] = edgenum;
}
 
inline int read(){
    int f = 1, val = 0; char ch = getchar();
    while ((ch < '0' || ch > '9') && (ch != '-')) ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') val = (val << 3) + (val << 1) + ch - '0', ch = getchar();
    return val * f;
}
 
int dist[maxn];
bool vis[maxn];
#define pii pair<int, int>
priority_queue< pii, vector< pii >, greater< pii > > Qmin;
const int INF = 1000000007;
inline void Dijkstra(int s){
    for (int i = 0; i <= n; ++i){
        vis[i] = false;
        dist[i] = INF;
    }
    dist[s] = 0; Qmin.push( make_pair(0, s) );
    for (int i = 0; i <= n; ++i){
        while (!Qmin.empty() && vis[Qmin.top().second]) Qmin.pop();
        if (Qmin.empty()) break;
        int u = Qmin.top().second; Qmin.pop();
        vis[u] = true;
        for (int e = head[u]; e; e = nxt[e]){
            int v = vet[e], cost = val[e];
            if (dist[v] > dist[u] + cost){
                dist[v] = dist[u] + cost;
                Qmin.push( make_pair(dist[v], v) );
            }
        }
    }
}
 
int main(){
    n = read(); m = read(); c = read();
    for (int i = 1; i <= m; ++i){
        int u = read(), v = read(), w = read();
        addedge(u, v, w);
    }
     
    for (int i = 0; i <= n; ++i){
        for (int j = 0; j < 20; ++j){
            int to = i ^ (1 << j);
            if (to <= n) addedge(i, to, c * (1 << j));
        }
    }
     
    int A = read(), B = read();
    Dijkstra(A);
     
    printf("%d\n", dist[B]);
    return 0;
}

方法 2 的代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define pii pair<int,int>
using namespace std; const int maxn = 200007;
const int maxm = 3000007;
int n, m, C, lgn, A, B;
int edgenum, hea[maxn], vet[maxm], nxt[maxm], val[maxm];
inline void addedge(int u, int v, int cost){
++edgenum;
vet[edgenum] = v;
val[edgenum] = cost;
nxt[edgenum] = hea[u];
hea[u] = edgenum; //printf("%d -> %d (%d)\n", u, v, cost);
} inline int read(){
int f=1, val=0; char ch=getchar();
while ((ch<'0'||ch>'9')&&(ch!='-')) ch=getchar();
if (ch=='-') f=-1,ch=getchar();
while (ch>='0'&&ch<='9') val=(val<<3)+(val<<1)+ch-'0',ch=getchar();
return val*f;
} int dist[maxn];
bool vis[maxn];
priority_queue<pii, vector< pii >, greater< pii > > Qmin;
inline void Dijkstra(int s){
for (int i = 1; i <= n; ++i){
vis[i] = false;
dist[i] = 1000000000;
}
dist[s] = 0; Qmin.push(make_pair(0, s));
for (int i = 1; i <= n; ++i){
while (!Qmin.empty() && vis[Qmin.top().second]) Qmin.pop();
if (Qmin.empty()) break;
int u = Qmin.top().second; Qmin.pop();
vis[u] = true;
for (int e = hea[u]; e; e = nxt[e]){
int v = vet[e], cost = val[e];
if (dist[v] > dist[u] + cost) dist[v] = dist[u] + cost, Qmin.push(make_pair(dist[v], v));
}
}
} int main(){
n = read(); m = read(); C = read();
for (int i = 1; i <= m; ++i){
int u = read(), v = read(), cost = read();
addedge(u, v, cost);
}
lgn = floor(log2(n)) + 1;
n = (1 << lgn) - 1; for (int i = 1; i <= n; ++i){
for (int j = 0; j < lgn; ++j)
addedge(i, i ^ (1 << j), (1 << j) * C);
} A = read(); B = read();
Dijkstra(A); printf("%d\n", dist[B]);
return 0;
}

[Code+#4]最短路 解题报告的更多相关文章

  1. hdu 2544 最短路 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 题目意思:给出 n 个路口和 m 条路,每一条路需要 c 分钟走过.问从路口 1 到路口 n 需 ...

  2. 「2018-12-02模拟赛」T1 最短路 解题报告

    1.最短路(short.pas/cpp/in/out) 问题描述: 小 C 终于被小 X 感动了,于是决定与他看电影,然而小 X 距离电影院非常远,现在假设 每条道路需要花费小 X 的时间为 1,由于 ...

  3. 「ZJOI2016」解题报告

    「ZJOI2016」解题报告 我大浙的省选题真是超级神仙--这套已经算是比较可做的了. 「ZJOI2016」旅行者 神仙分治题. 对于一个矩形,每次我们从最长边切开,最短边不会超过 \(\sqrt{n ...

  4. ACM-ICPC 2017 Asia HongKong 解题报告

    ACM-ICPC 2017 Asia HongKong 解题报告 任意门:https://nanti.jisuanke.com/?kw=ACM-ICPC%202017%20Asia%20HongKon ...

  5. CH Round #56 - 国庆节欢乐赛解题报告

    最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...

  6. 二模13day1解题报告

    二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...

  7. LeetCode 解题报告索引

    最近在准备找工作的算法题,刷刷LeetCode,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中......                        ...

  8. POJ 1001 解题报告 高精度大整数乘法模版

    题目是POJ1001 Exponentiation  虽然是小数的幂 最终还是转化为大整数的乘法 这道题要考虑的边界情况比较多 做这道题的时候,我分析了 网上的两个解题报告,发现都有错误,说明OJ对于 ...

  9. 2014 ACM/ICPC 鞍山赛区现场赛 D&amp;I 解题报告

    鞍山现场赛结束了呢-- 我们出的是D+E+I三道题-- 吾辈AC掉的是D和I两道,趁着还记得.先在这里写一写我写的两道水题D&I的解题报告吧^_^. D题的意思呢是说星云内有一堆排成一条直线的 ...

随机推荐

  1. Gym - 101350A Sherlock Bones(思维)

    The great dog detective Sherlock Bones is on the verge of a new discovery. But for this problem, he ...

  2. Servlet 学习

    3.1 概念 运行在服务器端的小程序 Servlet 就是一个接口 定义JAVA类被浏览器访问(Tomact 识别)的规则 将来 我们需要自定义一个类 实现servlet 接口 重写方法 3.2 快速 ...

  3. 网页三剑客之HTML

    Web服务本质 import socket def handle_request(client): request_data = client.recv(1024) print(request_dat ...

  4. Hbase 元数据一致性检查(转)

    最近在学习HBase先关的知识,顺便做一下笔记,以加深知识的了解和掌握. Hbase常用工具 文件检测修复工具 hbase hbck -help 常用选项: -details 显示所有region检查 ...

  5. CSS基础选择器(选择器的优先级),CSS样式块( 长度/颜色/显示方式/文本样式),盒模型组成,盒模型-block,盒模型布局

    CSS基础选择器 (1)id选择器:   #       =>  标签拥有 id="user"  属性 <style> #user { width: 200px; ...

  6. PyQt5开发环境搭建

    一 写在开头1.1 本节内容开个新坑—“PyQt5系列”,慢慢填.本文主要内容为PyQt5开发环境的搭建. 注意:PyQt 5.10以上的版本在Python 3.6中有BUG,PyQt 5.10版本是 ...

  7. Nmpy函数总结

    函数和方法method总览 这是个Numpy函数和方法分类排列目录. 创建数组 arange, array, copy, empty, empty_like, eye, fromfile, fromf ...

  8. word20161226

    1. condensed 英[kən'denst]美[kənˈdɛnst]v. (使) 变稠或变浓,浓缩( condense的过去式和过去分词 ); (使) 凝结; 简说,摘要,简述;[例句]The ...

  9. PHP 【二】

    EOF EOF(heredoc)是一种在命令行shell(如sh.csh.ksh.bash.PowerShell和zsh)和程序语言(像Perl.PHP.Python和Ruby)里定义一个字符串的方法 ...

  10. C++设计模式——命令模式

    什么是命令模式? 在GOF的<设计模式:可复用面向对象软件的基础>一书中对命令模式是这样说的:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以 ...