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. 基于USB网卡适配器劫持DHCP Server嗅探Windows NTLM Hash密码

    catalogue . DHCP.WPAD工作过程 . python Responder . USB host/client adapter(USB Armory): 包含DHCP Server . ...

  2. Spring的事务机制

    ---恢复内容开始--- 内定的=>(只需要在xml 中添加一个bean) 在xml 中添加 <bean id="listener" class="com.t ...

  3. HDU 1051(处理木棍 贪心)

    题意是处理一批木棍,如果当前处理的木棍长度和重量均大于前一根木棍的长度和重量,则处理当前木棍花费为 0,否则花费为 1. 用结构体存储木棍信息,将木棍按照长度从小到大排序,若长度相等则按照重量从小到大 ...

  4. Promise异步操作

    Promise是es6中新增加的类(new Promise),目的为了管理JS中异步编程,也叫“Promise”设计模式 Promise用来解决异步问题.本身是同步的,只是用来管理异步编程的一种模式 ...

  5. QGE 在齐次 Besov 空间中的准则

    在 [Zhang, Zujin. On the blow-up criterion for the quasi-geostrophic equations in homogeneous Besov s ...

  6. hibernate之Session对象

    Session对象:数据库的核心对象 增删改查 ...java public class UserDao { public void addUser(User user) { //使用hibernat ...

  7. Database学习 - mysql 视图/触发器/函数

  8. Android app中的so库和CPU架构

    一.android目前有几种cpu架构? 早期的Android系统几乎只支持ARMv5的CPU架构,目前支持七种CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MI ...

  9. [dts]Device Tree机制【转】

    转自:https://www.cnblogs.com/aaronLinux/p/5496559.html 转自:http://blog.csdn.net/machiner1/article/detai ...

  10. 【原创】大数据基础之Marathon(1)简介、安装、使用

    marathon 1.6.322 官方:https://mesosphere.github.io/marathon/ 一 简介 Marathon is a production-grade conta ...