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. 应用调试(一)strace

    目录 编译 使用 原理 深入文档 title: 应用调试(一)strace date: 2019/1/15 23:35:14 toc: true --- 编译 #tar -xjf strace-4.5 ...

  2. 流程控制if、while、for

    if判断   if判断想执行第一个条件,if后的判断必须是True 1 什么是if判断 判断一个条件如果成立则做...不成立则做....2 为何要有if判断 让计算机能够像人一样具有判断的能力3 如何 ...

  3. shell使用lftp连接ftp和sftp,并可以指定私钥

    lftp连接ftp在脚本中可以 lftp -c "open username:password@host:port; ls /Friso/20180822/click/mobile/SUCC ...

  4. LOJ #2116 Luogu P3241「HNOI2015」开店

    好久没写数据结构了 来补一发 果然写的时候思路极其混乱.... LOJ #2116 Luogu P3241 题意 $ Q$次询问,求树上点的颜色在$ [L,R]$中的所有点到询问点的距离 强制在线 询 ...

  5. Revit手工创建族(转)

    http://www.cnblogs.com/greatverve/p/revit-family.html 手工创建族 1.画两个参考平面. 图3001 2.点击族类型,添加参数. 图3002,300 ...

  6. pom文件报错org.apache.maven.archiver.mavenarchiver.getmanifest

    eclipse导入新的maven项目时,pom.xml第一行报错: org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.mav ...

  7. 51nod 1228、1258 序列求和

    这里一次讲两题...貌似都是板子? 所以两题其实可以一起做 [雾 noteskey 总之就是伯努利数的两道入门题啦,就是第二道有点鬼畜了,居然要任意模数的!(好吧是 1e9+7 但也没什么区别了) 伯 ...

  8. nslookup get public/external IP

    nslookup myip.opendns.com resolver1.opendns.com Server: resolver1.opendns.comAddress: 208.67.222.222 ...

  9. Spring扩展自定义的XML标签

    在网上搜了许多,感觉不够全面,就找了官方文档,下面记录如何找到对应的文档进入 网上许多博客都是以dateformat为实例进行编写的,通过官方的foo,能够学到更多的东西,下面贴一段代码,在官方示例上 ...

  10. JS函数可以再添加属性(包括方法)

    1 前言 JS函数可以再添加属性(包括方法),这个有点有趣,记录一下. 2 代码 <!DOCTYPE html> <html> <head> <title&g ...