牛客网NOIP赛前集训营-提高组(第六场)-A-最长路[拓扑排序+hash+倍增]
题意
给定一个 \(n\) 点 \(m\) 边的边权非负的有向图,边有字符,求以每个点为开头的最长路字典序最小的路径 \(hash\) 值。
\(n,m\leq 10^6\)
分析
首先建反图拓扑排序后入度不为0的点的答案为 \(inf\) 。
在 \(dep\) 相同时,怎么比较两种转移的优劣?注意到建完反图之后可以通过判定两个转移第一个字典序不同的位置的大小,可以倍增\(+hash\) 实现。
总时间复杂度为 \(O(20*(n+m))\)。
代码
#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=1e6 + 7,mod=998244353;
int n,m,edc,hd=1,tl;
int head[N],ind[N],q[N],dep[N],to[N][21];
LL h[N][21],bin[N];
struct edge{
int last,to,c;
edge(){}edge(int last,int to,int c):last(last),to(to),c(c){}
}e[N*2];
void Add(int a,int b,int c){
e[++edc]=edge(head[a],b,c),head[a]=edc;++ind[b];
}
bool better(int x,int y){
for(int i=20;~i;--i)
if(h[x][i]==h[y][i]) x=to[x][i],y=to[y][i];
return h[x][0]<h[y][0];
}
void topo(){
rep(i,1,n) if(!ind[i]) q[++tl]=i,dep[i]=1;
for(;hd<=tl;++hd){
int u=q[hd];
rep(i,1,20){
to[u][i]=to[to[u][i-1]][i-1];
h[u][i]=(h[u][i-1]+h[to[u][i-1]][i-1]*bin[1<<i-1])%mod;
}
go(u){
if(dep[u]+1>dep[v]) dep[v]=dep[u]+1,to[v][0]=u,h[v][0]=e[i].c;
else if(dep[u]+1==dep[v]){
if(!to[v][0]||e[i].c<h[v][0]||(e[i].c==h[v][0]&&better(u,to[v][0])))
to[v][0]=u,h[v][0]=e[i].c;
}
if(--ind[v]==0) q[++tl]=v;
}
}
rep(i,1,n)
if(ind[i]) puts("Infinity");
else printf("%lld\n",29*h[i][20]%mod);
}
int main(){
n=gi(),m=gi();
for(int i=1,a,b,c;i<=m;++i){
a=gi(),b=gi(),c=gi();
Add(b,a,c);
}
bin[0]=1;
rep(i,1,N-1) bin[i]=1ll*bin[i-1]*29%mod;
topo();
return 0;
}
还有一种做法,将所有同层的点根据字典序优劣排序后转移到下一层,可以归纳证明。
#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=1e6 + 7,mod=998244353,inf=0x3f3f3f3f;
typedef pair<int,int> pii;pii f[N];
#define mp make_pair
int n,m,edc,hd=1,tl;
int head[N],ind[N],q[N],dep[N],rk[N],h[N];
struct edge{
int last,to,c;
edge(){}edge(int last,int to,int c):last(last),to(to),c(c){}
}e[N*2];
void Add(int a,int b,int c){
e[++edc]=edge(head[a],b,c),head[a]=edc;++ind[b];
}
vector<int>G[N];
bool cmp(int a,int b){
return f[a]<f[b];
}
void topo(){
rep(i,1,n) if(!ind[i]) q[++tl]=i,dep[i]=1,f[i]=mp(0,0);
else f[i]=mp(inf,inf);
for(;hd<=tl;++hd){
int u=q[hd];
G[dep[u]].pb(u);
go(u){
Max(dep[v],dep[u]+1);
if(--ind[v]==0) q[++tl]=v;
}
}
rep(j,1,n){
for(auto u:G[j])
go(u)if(dep[u]+1==dep[v]){
if(mp(e[i].c,rk[u])<f[v]){
f[v]=mp(e[i].c,rk[u]);
h[v]=(1ll*h[u]*29+e[i].c)%mod;
}
}
sort(G[j+1].begin(),G[j+1].end(),cmp);
rep(i,0,(int)G[j+1].size()-1) rk[G[j+1][i]]=i;
}
rep(i,1,n)
if(ind[i]) puts("Infinity");
else printf("%lld\n",1ll*29*h[i]%mod);
}
int main(){
n=gi(),m=gi();
for(int i=1,a,b,c;i<=m;++i){
a=gi(),b=gi(),c=gi();
Add(b,a,c);
}
topo();
return 0;
}
牛客网NOIP赛前集训营-提高组(第六场)-A-最长路[拓扑排序+hash+倍增]的更多相关文章
- 牛客网NOIP赛前集训营-普及组(第二场)和 牛客网NOIP赛前集训营-提高组(第二场)解题报告
目录 牛客网NOIP赛前集训营-普及组(第二场) A 你好诶加币 B 最后一次 C 选择颜色 D 合法括号序列 牛客网NOIP赛前集训营-提高组(第二场) A 方差 B 分糖果 C 集合划分 牛客网N ...
- 牛客网NOIP赛前集训营-提高组(第二场)A 方差
链接:https://www.nowcoder.com/acm/contest/173/A来源:牛客网 题目描述 一个长度为 m 的序列 b[1...m] ,我们定义它的方差为 ,其中 表示序列的平 ...
- [牛客网NOIP赛前集训营-提高组(第一场)]C.保护
链接:https://www.nowcoder.com/acm/contest/172/C来源:牛客网 题目描述 C国有n个城市,城市间通过一个树形结构形成一个连通图.城市编号为1到n,其中1号城市为 ...
- 牛客网NOIP赛前集训营-提高组(第一场)
牛客的这场比赛感觉真心不错!! 打得还是很过瘾的.水平也比较适合. T1:中位数: 题目描述 小N得到了一个非常神奇的序列A.这个序列长度为N,下标从1开始.A的一个子区间对应一个序列,可以由数对[l ...
- 比赛总结——牛客网 NOIP赛前集训营提高组模拟第一场
第一场打的很惨淡啊 t1二分+前缀最小值没想出来,20分的暴力也挂了,只有10分 t2数位dp,调了半天,结果因为忘了判0的特殊情况WA了一个点,亏死 t3emmmm.. 不会 imone说是DSU ...
- 牛客网NOIP赛前集训营-提高组(第一场)B 数数字
数数字 思路: 数位dp 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include< ...
- 牛客网NOIP赛前集训营-提高组(第一场)A 中位数
中位数 思路: 二分答案 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include< ...
- 牛客网NOIP赛前集训营 提高组 第5场 T2 旅游
[题解] 我们可以发现不在最小生成树上的边一定不能多次经过,因为一条不在最小生成树上的边(u,v)的边权比最小生成树上(u,v)之间的路径更长,选择不在最小生成树上的边一定不划算. 我们还需要确定最小 ...
- 牛客网NOIP赛前集训营-提高组(第四场)游记
牛客网NOIP赛前集训营-提高组(第四场)游记 动态点分治 题目大意: \(T(t\le10000)\)组询问,求\([l,r]\)中\(k(l,r,k<2^{63})\)的非负整数次幂的数的个 ...
- 牛客网NOIP赛前集训营-提高组(第四场)B区间
牛客网NOIP赛前集训营-提高组(第四场)B区间 题目描述 给出一个序列$ a_1 \dots a_n$. 定义一个区间 \([l,r]\) 是好的,当且仅当这个区间中存在一个 \(i\),使得 ...
随机推荐
- [翻译] M13ProgressSuite
M13ProgressSuite https://github.com/Marxon13/M13ProgressSuite A set of classes used to display progr ...
- SCCM2012安装、配置
1.sql server2012,排序规则选择:SQL_Latin1_General_CP1_CI_AS1.扩展AD架构2.打开ad用户和计算机,高级--system 容器授予 sccm服务器 完全控 ...
- Python初学者第二十三天 函数进阶(2)装饰器
装饰器: 需求----> 写一个功能,测试其他同事函数的调用效率. 第一版:功能版 import time def func(): time.sleep(0.2) print('非常复杂') d ...
- Web通信协议:OSI、TCP、UDP、Socket、HTTP、HTTPS、TLS、SSL、WebSocket、Stomp
1 各层的位置 1.1 OSI七层模型全景图 OSI是Open System Interconnect的缩写,意为开放式系统互联. 1.2 五层网络协议 在七层的基础上, ...
- Programming Assignment 5: Burrows–Wheeler Data Compression
编程作业五 作业链接:Burrows-Wheeler Data Compression & Checklist 我的代码:MoveToFront.java & CircularSuff ...
- vs环境变量学习
1. 查看vs环境变量: 在项目设置中的任何路径.目录编辑项目下,右下角有个“宏”,点开即可见所有vs环境变量的当前设置...听说还有其它地方,没看到. 2.上边的“宏”,即是英文的vs环境变量 3. ...
- Ceph PG介绍及故障状态和修复
1 PG介绍pg的全称是placement group,中文译为放置组,是用于放置object的一个载体,pg的创建是在创建ceph存储池的时候指定的,同时跟指定的副本数也有关系,比如是3副本的则会有 ...
- Linux centos修改防火墙为iptables
防火墙配置 CentOS 7默认使用的是firewall作为防火墙,这里改为iptables防火墙. firewall操作: # service firewalld status; #查看防火墙状态 ...
- access数据库及其分页的方法
首先access数据库的话,感觉针对比较小型的网站比较适合.携带方便,不需要按照特定的sql环境. 当然如果使用access数据库的话 1.首先你先要下载办公五合一(access也是其中之一) 2.w ...
- Windows与Linux之间的文件自动同步
问题:在工作中遇到一个场景,需要每天定时将Linux机器上的文件自动同步到Windows机器上. 解决方案有两个: 1.在Windows 机器上设置共享目录,然后在Linux机器上挂载共享 目录,每天 ...