@description@

企鹅国中有 N 座城市,编号从 1 到 N 。

对于任意的两座城市 i 和 j ,企鹅们可以花费 (i xor j) * C 的时间从城市 i 走到城市 j ,这里 C 为一个给定的常数。

当然除此之外还有 M 条单向的快捷通道,第 i 条快捷通道从第 Fi 个城市通向第 Ti 个城市,走这条通道需要消耗 Vi 的时间。

现在来自 Penguin Kingdom University 的企鹅豆豆正在考虑从城市 A 前往城市 B 最少需要多少时间?

input

输入第一行包含三个整数 N, M, C (1 ≤ N ≤ 10^5, 1 ≤ M ≤ 3*10^5, 1 ≤ C ≤ 100),表示企鹅国城市的个数、快捷通道的个数以及题面中提到的给定的常数 C。

接下来的 M 行,每行三个正整数 Fi, Ti, Vi (1 ≤ Fi ≤ N, 1 ≤ Ti ≤N, 1 ≤ Vi ≤ 100),分别表示对应通道的起点城市标号、终点城市标号和通过这条通道需要消耗的时间。

最后一行两个正整数 A, B,表示企鹅豆豆选择的起点城市标号和终点城市标号。

output

输出一行一个整数,表示从城市 A 前往城市 B 需要的最少时间。

simple input

7 2 10

1 3 1

2 4 4

3 6

simple output

34

simple explain

先从 3 走到 2 ,再从 2 通过通道到达 4 ,再从 4 走到 6。

@solution@

令人自闭(事实上是因为自己太弱的)的一道题 TAT。

我们有两类边:一般边 与 异或边。

一种特别暴力的想法就是,按题意给所有点之间连上这两类边,跑从 A 出发到 B 的最短路。但是由于异或边构成的是完全图,导致这种想法并不可行。

然而我们注意到一般边的数量是在正常范围以内。而且我们可不可以利用异或的什么性质来简化图,减少异或边的数量?

这个时候就可以用位运算最基本的套路:拆位。即把二进制表示下的每一位分类讨论。

对于 i 到 j 的异或边,它的费用为 i xor j。我们将 i xor j 拆成若干个 2 的幂之和,对应到图上,即将 i 到 j 的异或边拆成若干个费用为 2 的幂的边组成的路径。

具体怎么搞呢?我们对于结点 i,只连出 i xor 2^0, i xor 2^1, ... 共 log 条边。这样, i 到 j 的最短路径就对应着原图中 i 到 j 的异或边。

而边数降低为 O(nlog n + M) 条,就可以该怎么跑最短路就怎么跑(当然 SPFA 还是该怎么卡就怎么卡)。

注意原本的点编号是 1~N,而新图必须拓展到 0~2^p (2^p > N) 拆位才不会拆出问题来。

@accepted code@

#include<cstdio>
#include<queue>
using namespace std;
const int MAXN = 200000;
const int MAXM = 500000;
const int INF = (1<<30);
struct edge{
int to, dis;
edge *nxt;
}edges[MAXM + 20*MAXN + 5], *adj[MAXN + 5], *ecnt=&edges[0];
void addedge(int u, int v, int w) {
edge *p = (++ecnt);
p->to = v, p->dis = w;
p->nxt = adj[u], adj[u] = p;
}
int dist[MAXN + 5], tot; bool vis[MAXN + 5];
struct node{
int pos, dis;
node(int _p=0, int _d=0):pos(_p), dis(_d){}
};
bool operator < (node a, node b) {
return a.dis > b.dis;
}
priority_queue<node>que;
void dijkstra(int S) {
que.push(node(S, 0));
for(int i=0;i<=tot;i++)
dist[i] = INF, vis[i] = false;
dist[S] = 0;
while( !que.empty() ) {
node t = que.top(); que.pop();
if( vis[t.pos] ) continue;
vis[t.pos] = true;
for(edge *p=adj[t.pos];p!=NULL;p=p->nxt) {
if( t.dis + p->dis < dist[p->to] ) {
dist[p->to] = t.dis + p->dis;
que.push(node(p->to, dist[p->to]));
}
}
}
}
int main() {
int N, M, A, B, C; scanf("%d%d%d", &N, &M, &C);
for(int i=1;i<=M;i++) {
int F, T, V;
scanf("%d%d%d", &F, &T, &V);
addedge(F, T, V);
}
scanf("%d%d", &A, &B);
for(tot = 1;tot <= N;tot <<= 1);
for(int i=0;i<tot;i++)
for(int p=1;p<tot;p<<=1)
addedge(i, i^p, p*C);
dijkstra(A); printf("%d\n", dist[B]);
}

@details@

自己在做这道题的时候,发现连续通过两条异或边是不优秀的,因为 (i xor j + j xor k) * C >= (i xor j xor j xor k) * C = (i xor k) * C。然后就顺着这个方向走了好久……

好像有想到过拆位,然后一瞬间走神就忘记了……

我太弱了 TAT。

@loj - 6354@「CodePlus 2018 4 月赛」最短路的更多相关文章

  1. LOJ#6354. 「CodePlus 2018 4 月赛」最短路[最短路优化建图]

    题意 一个 \(n\) 个点的完全图,两点之间的边权为 \((i\ xor\ j)*C\) ,同时有 \(m\) 条额外单向路径,问从 \(S\) 到 \(T\) 的最短路. \(n\leq 10^5 ...

  2. 【LibreOJ】#6354. 「CodePlus 2018 4 月赛」最短路 异或优化建图+Dijkstra

    [题目]#6354. 「CodePlus 2018 4 月赛」最短路 [题意]给定n个点,m条带权有向边,任意两个点i和j还可以花费(i xor j)*C到达(C是给定的常数),求A到B的最短距离.\ ...

  3. @loj - 6353@「CodePlus 2018 4 月赛」组合数问题 2

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 请你找到 k 个不同的组合数,使得对于其中任何一个组合数 \(C ...

  4. loj #6302. 「CodePlus 2018 3 月赛」寻找车位【线段树+单调队列】

    考虑静态怎么做:枚举右边界,然后枚举上边界,对应的下边界一定单调不降,单调栈维护每一列从当前枚举的右边界向左最长空位的长度,这样是O(nm)的 注意到n>=m,所以m<=2000,可以枚举 ...

  5. 「CodePlus 2018 4 月赛」最短路

    $n \leq 100000$,$m \leq 500000$的有向图,两点之间还可以以$a \ \ xor \ \ b$的代价从$a$到$b$,问$s$到$t$的最短路. 被自己蠢哭QAQ 首先两个 ...

  6. [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞

    [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞 试题描述 到河北省 见斯大林 / 在月光下 你的背影 / 让我们一起跳舞吧 うそだよ~ 河北省怎么可能有 Stalin. ...

  7. loj #6250. 「CodePlus 2017 11 月赛」找爸爸

    #6250. 「CodePlus 2017 11 月赛」找爸爸 题目描述 小 A 最近一直在找自己的爸爸,用什么办法呢,就是 DNA 比对. 小 A 有一套自己的 DNA 序列比较方法,其最终目标是最 ...

  8. [LOJ 6249]「CodePlus 2017 11 月赛」汀博尔

    Description 有 n 棵树,初始时每棵树的高度为 H_i,第 i 棵树每月都会长高 A_i.现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不 ...

  9. [LOJ 6248]「CodePlus 2017 11 月赛」晨跑

    Description “无体育,不清华”.“每天锻炼一小时,健康工作五十年,幸福生活一辈子” 在清华,体育运动绝对是同学们生活中不可或缺的一部分.为了响应学校的号召,模范好学生王队长决定坚持晨跑.不 ...

随机推荐

  1. 记录centos7下tomcat部署war包过程

    记录centos7下tomcat部署war包过程 1.官网下载tomcat安装包.gz结尾的 2.上传到/usr/local/ ,并解压到tomcat目录下 3.进入tomcat/bin目录,运行./ ...

  2. nginx日志修改时间格式为年月日时分秒

    先解除这段注释,使用自定义日志格式 $time_iso8601 生成格式:--20T09::+: $time_local 生成格式: /Apr/::: + 还是选择年月日时分秒看起来舒服一点

  3. 实用Jupyter Notebook扩展工具——提升你的工作效率

    Jupyter Notebook 现已成为数据分析,机器学习的必备工具.因为它可以让数据分析师集中精力向用户解释整个分析过程.通过安装一些扩展工具,可以让你在Jupyter Notebook上的工作效 ...

  4. 插头DP智障操作合集

    今天一共四道插头DP[其实都差不多],智障错误出了不下五个:D 来,让我好好数落我自己一下 直接写代码注释里吧 Eat the Trees #include<iostream> #incl ...

  5. Ubuntu 12.04 安装 IQQ

    1. 安装 IQQ 首先应安装jdk包 2. 百度网盘下载: http://pan.baidu.com/share/home?uk=3071047022 3. 运行 (1) Linux用户给IQQ-1 ...

  6. 推荐一个 Laravel admin 后台管理插件

    如何优雅的写代码,我想是每位程序员的心声.自从15年初第一次接触 Laravel 4.2 开始,我就迷上使用 Laravel 框架了.我一直都想找个时间好好写写有关 Laravel 的使用文章,由浅入 ...

  7. LintCode刷题笔记-- Distinct Subsequences

    标签:动态规划 题目描述: Given a string S and a string T, count the number of distinct subsequences of T in S. ...

  8. Linux安装MariaDB(Mysql)和简单配置 mariadb

    Linux安装MariaDB(Mysql)和简单配置 1.安装MariaDB 安装命令 yum -y install mariadb mariadb-server 安装完成MariaDB,首先启动Ma ...

  9. NFS客户端挂载目录后无写入权限的解决方案

    转载至:https://blog.csdn.net/younger_china/article/details/52089337 在客户机通过 mount -o rw -t nfs 192.168.1 ...

  10. 微服务开源生态报告 No.6

    「微服务开源生态报告」,汇集各个开源项目近期的社区动态,帮助开发者们更高效的了解到各开源项目的最新进展. 社区动态包括,但不限于:版本发布.人员动态.项目动态和规划.培训和活动. 非常欢迎国内其他微服 ...