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. 存储与服务器的连接方式对比(DAS,NAS,SAN)

    存储分类简介 磁盘存储市场上,存储分类根据服务器类型分为:封闭系统的存储和开放系统的存储,封闭系统主要指大型机,AS400等服务器,开放系统指基于包括Windows.UNIX.Linux等操作系统的服 ...

  2. 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借助TopSelf、服务类】)

    一. IIS部署 比如在MVC框架中集成了Quartz.Net定时调度,此时该调度系统会随着MVC框架被挂在IIS下,IIS会进程回收,所以大部分开发都会遇到Quartz挂在IIS下一段时间不好用. ...

  3. HTML(一)HTML基础语法(HTML简介,HTML文档声明)

    HTML 概念介绍 [概念] (Hyper Text Markup Language)超文本标记语言,是用来描述网页的一种语言 超文本(Hyper Text):不只包括文本,也可以包括图片.链接.音乐 ...

  4. Beamer制作索引

    \documentclass{beamer} \usepackage{multicol} \usepackage{makeidx} \newenvironment{theindex}{% \let\i ...

  5. SecureCRT的安装与破解(过程很详细!!!)

    SecureCRT的安装与破解(过程很详细!!!) 使用SecureCRT可以方便用户在windows环境下对linux主机进行管理,这里为大家讲一下SecureCRT的破解方法,仅供大家参考学习: ...

  6. anaconda3安装cv2模块(python3.6)

  7. vue 3.0

    参照网址: https://blog.csdn.net/qq_36407748/article/details/80739787

  8. MySql新增表的字段,删除表字段

    1增加两个字段: create table id_name(id int,name varchar(20));//创建原始数据表 alter table id_name add age int,add ...

  9. vue项目移植tinymce踩坑

    转载:https://segmentfault.com/a/1190000012791569?utm_source=tag-newest 2019-2-18 貌似这篇文章帮了大家一些小忙最近tinym ...

  10. C# .Net List<T>中Remove()、RemoveAt()、RemoveRange()、RemoveAll()的区别,List<T>删除汇总

    在List<T>中删除主要有Remove().RemoveAt().RemoveRange().RemoveAll()这几个方法.下面一一介绍使用方法和注意点. 我们以List<st ...