题面

一道特殊的最短路题。

给一个

n

n

n 个点

m

m

m 条有向边的图,每条边上有数字

0

\tt0

0 或

1

\tt1

1 ,定义一个路径的长度为这个路径上依次经过的边上的数字拼在一起后在二进制下的值(前导

0

\tt0

0 对该路径长度没有贡献)。现在需要你求出从

1

1

1 号点出发,到

2

n

2\sim n

2∼n 号点的路径的长度的最小值。

n

1

0

6

,

m

2

1

0

6

.

n\leq10^6,m\leq2\cdot10^6.

n≤106,m≤2⋅106.

题解 & CODE

我们考虑该二进制路径的特性,前导

0

\tt0

0 是没有贡献的,因此

1

1

1 号点能直接通过

0

\tt0

0 走到的点肯定先处理出来。然后,路径上就必定有一个

1

\tt1

1 了,第一个

1

\tt1

1 的位数越高,路径长度就一定越大,所以接下来可以基于路径长度来简化该最短路。

我们根据首个

1

1

1 的位数来对图分层,此时进行 bfs,每次把该层的所有点拿出来,拿出来的时候就按照路径从小到大站成一列了,然后从前到后扩张每个点,优先走

0

0

0 边。这样可以线性地得到下一层所有点的路径长度,以及顺便把下一层的点按照路径长度从小到大放进了队列里。

时间复杂度

O

(

n

+

m

)

O(n+m)

O(n+m) 。


笔者的第二种方法仅供娱乐。

考虑取模过后(哈希过后)失去相对大小信息,无法比较,高精度又太慢。这个时候就可以用离散化

我们对

D

i

j

k

s

t

r

a

\rm Dijkstra

Dijkstra 进行改进,在求最短路的同时,求出每个点路径长度的排名(长度相等排名相同)。然后我们就可以依次比较 转移前驱的排名转移边 来对未确定的点进行择优,以及确定新排名时判断重复。

代码简单,只需要将传统 手写堆 优化

D

i

j

k

s

t

r

a

\rm Dijkstra

Dijkstra 进行小小的翻修。

时间复杂度

O

(

n

log

n

)

O(n\log n)

O(nlogn) 。输麻了

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<random>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 2000005
#define LL long long
#define DB double
#define lowbit(x) (-(x) & (x))
#define ENDL putchar('\n')
#define FI first
#define SE second
int xchar() {
static const int maxn = 100000;
static char b[maxn];
static int len = 0,pos = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
//#define getchar() xchar()
LL read() {
LL f=1,x=0;int s = getchar();
while(s < '0' || s > '9') {if(s<0) return -1;if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar('0'+(x%10));}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) {putchar('-');x = -x;}
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);} const int MOD = 1000000007;
int n,m,s,o,k;
int hd[MAXN],v[MAXN<<1],nx[MAXN<<1],w[MAXN<<1],cne;
void ins(int x,int y,int z) {
nx[++ cne] = hd[x]; v[cne] = y; w[cne] = z; hd[x] = cne;
}
int dp[MAXN],rk[MAXN];
int pr[MAXN],nw[MAXN];
int mg(int a,int b) {
if(pr[a] == pr[b]) return nw[a] < nw[b] ? a:b;
return pr[a] < pr[b] ? a:b;
}
int tre[MAXN<<1];
void upd(int x,int y) {
tre[n+x] = y;
for(int s = (n+x)>>1;s>0;s >>= 1) {
tre[s] = mg(tre[s<<1],tre[s<<1|1]);
}return ;
}
int main() {
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
n = read();m = read();
for(int i = 1;i <= m;i ++) {
s = read();o = read();k = read();
ins(s,o,k);
}
for(int i = 0;i <= n;i ++) {
pr[i] = 0x3f3f3f3f; nw[i] = 1;
dp[i] = -1;
}
dp[1] = 0; pr[1] = 0; nw[1] = 0;
upd(1,1);
int t = 0;
for(int i = 1;i <= n;i ++) {
int tt = tre[1];
if(!tt) break;
if(t && (pr[tt] != pr[t] || nw[tt] != nw[t])) rk[tt] = rk[t] + 1;
else rk[tt] = rk[t];
t = tt;
for(int j = hd[t];j;j = nx[j]) {
int y = v[j],z = w[j];
if(rk[t] < pr[y] || (rk[t]==pr[y] && z < nw[y])) {
pr[y] = rk[t]; nw[y] = z;
dp[y] = (dp[t]<<1|z) % MOD;
upd(y,y);
}
}
upd(t,0);
}
for(int i = 2;i <= n;i ++) {
AIput(dp[i],i==n ? '\n':' ');
}
return 0;
}

【NOI P模拟赛】寻找道路(bfs,最短路)的更多相关文章

  1. [NOI P模拟赛] 传统艺能(子序列自动机、矩阵乘法,线段树)

    (2:00)OID:"完了,蓝屏了!"(代码全消失) 众人欢呼 OID:开机,"原题测试--" (30min later)OID 开始传统艺能: " ...

  2. luogu2296 [NOIp2014]寻找道路 (bfs)

    反着建边,从T bfs找合法的点,然后再正着bfs一下求最短路就行了 #include<bits/stdc++.h> #define pa pair<int,int> #def ...

  3. noip模拟赛 保留道路

    [问题描述] 很久很久以前有一个国家,这个国家有N个城市,城市由1,2,3,…,N标号,城市间有M条双向道路,每条道路都有两个属性g和s,两个城市间可能有多条道路,并且可能存在将某一城市与其自身连接起 ...

  4. 洛谷 P2296 寻找道路 —— bfs

    题目:https://www.luogu.org/problemnew/show/P2296 第一次用 Emacs 对拍,写了半天: 注意那个 is 赋值的地方很容易错,千万别反复赋值: 一道水题写了 ...

  5. 【NOI P模拟赛】最短路(树形DP,树的直径)

    题面 给定一棵 n n n 个结点的无根树,每条边的边权均为 1 1 1 . 树上标记有 m m m 个互不相同的关键点,小 A \tt A A 会在这 m m m 个点中等概率随机地选择 k k k ...

  6. NOIP模拟赛 寻找

    题目描述 “我有个愿望,我希望穿越一切找到你.” 这是个二维平面世界,平面上有n个特殊的果实,我从(0,0)点出发,希望得到尽量多的果实,但是出于某种特殊的原因,我的运动方式只有三种(假设当前我在(x ...

  7. 模拟赛20181015 Uva1078 bfs+四维dp

    题意:一张网格图,多组数据,输入n,m,sx,sy,tx,ty大小,起终点 接下来共有2n-1行,奇数行有m-1个数,表示横向的边权,偶数行有m个数,表示纵向的边权 样例输入: 4  4  1  1  ...

  8. noi.acNOIP模拟赛5-count

    题目链接 戳我 题意简述 你有一个n+1个数的序列,都是1~n,其中只有一个有重复,求每个长度的本质不同的子序列个数.\(mod 1e9+7\). sol 说起来也很简单,设相同的数出现的位置为\(l ...

  9. 【XJOI】【NOI考前模拟赛7】

    DP+卡常数+高精度/  计算几何+二分+判区间交/  凸包 首先感谢徐老师的慷慨,让蒟蒻有幸膜拜了学军的神题.祝NOI2015圆满成功 同时膜拜碾压了蒟蒻的众神QAQ 填填填 我的DP比较逗比……( ...

随机推荐

  1. STM32内存知识

    在了解STM32内存之前需要了解 MCU 的型号和MDK 中的.map 文件,很多刚学习 stm32 时都不会过多的去了解 MCU 的选型,是在太枯燥了.这里在从新了解一下,久了就熟悉了. 一.STM ...

  2. Linux文件拷贝脚本

    在工作中,我们经常遇到要从Linux服务器拷贝日志至本地或者定期清理日志的需求,在服务器上,大型系统的日志是按模块存储的,这就导致日志的文件目录较多且层级不统一.我们从众多的目录手工筛选要下载或者删除 ...

  3. 【转载】浅谈大规模k8s集群关于events的那些坑

    原文链接:一流铲屎官二流程序员[浅谈大规模k8s集群关于events的那些坑] 背景 随着k8s集群规模的增加,集群内的object数量也与日俱增,那么events的数量也会伴随其大量增加,那么当用户 ...

  4. Java开发学习(五)----bean的生命周期

    一.什么是生命周期 首先理解下什么是生命周期? 从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期. bean生命周期是什么? bean对象从创建到销毁的整体过程. bean生命周期 ...

  5. HDLBits->Circuits->Arithmetic Circuitd->3-bit binary adder

    Verilog实例数组 对于一个定义好的简单module,例如加法器之类,如果我们要对其进行几十次几百次的例化,并且这些例化基本都是相同的形式,那么我们肯定不能一个个的单独对其进行例化,此时我们就可以 ...

  6. 关闭windows更新、设置自启动、提高开发机性能

    做Java开发的朋友都知道,每次开机启动一堆的软件和工具,包括未写完的文档,是非常花时间的,加上一桌面的快捷方式,往往不是那么容易直接找到.windows的自动更新往往在凌晨自动启动,导致很多软件被异 ...

  7. JDBC:批处理

    1.批处理: 当要执行某条SQL语句很多次时.例如,批量添加数据:使用批处理的效率要高的多. 2.如何实现批处理 实践: package com.dgd.test; import java.io.Fi ...

  8. 攻防世界MISC进阶区 61-63

    61.肥宅快乐题 得到swf文件,但是用PotPlayer打不开,用浏览器应该可以打开,打开后可以在npc的对话中看到一段base64 解密后就可以得到flag 62.warmup 得到一张png和一 ...

  9. 在eclipse配置javafx

    JAVA学习中,遇到了这个问题,解决方法记录一下(我用的jdk11) 最新几版的eclipse中没有javafx,需要自己进行手动配置,先下载一下javafx的包,解压,找到lib文件夹(主要用的是这 ...

  10. 各种Git Bash乱码解决

    乱码情景一: 当使用git log 出现乱码时,修改 %GIT_HOME%\etc\gitconfig 文件,加入如下内容: [gui] encoding = utf-8[i18n] commiten ...