题意

给定一个 \(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+倍增]的更多相关文章

  1. 牛客网NOIP赛前集训营-普及组(第二场)和 牛客网NOIP赛前集训营-提高组(第二场)解题报告

    目录 牛客网NOIP赛前集训营-普及组(第二场) A 你好诶加币 B 最后一次 C 选择颜色 D 合法括号序列 牛客网NOIP赛前集训营-提高组(第二场) A 方差 B 分糖果 C 集合划分 牛客网N ...

  2. 牛客网NOIP赛前集训营-提高组(第二场)A 方差

    链接:https://www.nowcoder.com/acm/contest/173/A来源:牛客网 题目描述 一个长度为 m 的序列 b[1...m] ,我们定义它的方差为 ,其中  表示序列的平 ...

  3. [牛客网NOIP赛前集训营-提高组(第一场)]C.保护

    链接:https://www.nowcoder.com/acm/contest/172/C来源:牛客网 题目描述 C国有n个城市,城市间通过一个树形结构形成一个连通图.城市编号为1到n,其中1号城市为 ...

  4. 牛客网NOIP赛前集训营-提高组(第一场)

    牛客的这场比赛感觉真心不错!! 打得还是很过瘾的.水平也比较适合. T1:中位数: 题目描述 小N得到了一个非常神奇的序列A.这个序列长度为N,下标从1开始.A的一个子区间对应一个序列,可以由数对[l ...

  5. 比赛总结——牛客网 NOIP赛前集训营提高组模拟第一场

    第一场打的很惨淡啊 t1二分+前缀最小值没想出来,20分的暴力也挂了,只有10分 t2数位dp,调了半天,结果因为忘了判0的特殊情况WA了一个点,亏死 t3emmmm.. 不会 imone说是DSU ...

  6. 牛客网NOIP赛前集训营-提高组(第一场)B 数数字

    数数字 思路: 数位dp 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include< ...

  7. 牛客网NOIP赛前集训营-提高组(第一场)A 中位数

    中位数 思路: 二分答案 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include< ...

  8. 牛客网NOIP赛前集训营 提高组 第5场 T2 旅游

    [题解] 我们可以发现不在最小生成树上的边一定不能多次经过,因为一条不在最小生成树上的边(u,v)的边权比最小生成树上(u,v)之间的路径更长,选择不在最小生成树上的边一定不划算. 我们还需要确定最小 ...

  9. 牛客网NOIP赛前集训营-提高组(第四场)游记

    牛客网NOIP赛前集训营-提高组(第四场)游记 动态点分治 题目大意: \(T(t\le10000)\)组询问,求\([l,r]\)中\(k(l,r,k<2^{63})\)的非负整数次幂的数的个 ...

  10. 牛客网NOIP赛前集训营-提高组(第四场)B区间

    牛客网NOIP赛前集训营-提高组(第四场)B区间 题目描述 给出一个序列$ a_1  \dots   a_n$. 定义一个区间 \([l,r]\) 是好的,当且仅当这个区间中存在一个 \(i\),使得 ...

随机推荐

  1. [翻译] JKLLockScreenViewController

    JKLLockScreenViewController https://github.com/tiny2n/JKLLockScreenViewController Overview It is Loc ...

  2. iOS设计模式 - 访问者

    iOS设计模式 - 访问者 原理图 说明 表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 1.Visitor 抽象访问者角色,为该对象结构中具 ...

  3. HTML基础标签的综合应用案例(颜色、斜体、加粗、下划线、a标签、无序列表、有序列表)

    什么是HTML l HTML(HyperText Mark-up Language)即超文本标记语言或超文本标签语言. l 何为超文本:“超文本”可以实现页面内可以包含图片.链接,甚至音乐.程序等. ...

  4. November 20th 2016 Week 47th Sunday

    Learn from yesterday, live for today, look to tomorrow. 学习昨天,活在今天,展望明天. There is always room at the ...

  5. ZT 4.3 android bluetooth hfp分析

    4.3 android bluetooth hfp分析 2013-08-20 20:16 592人阅读 评论(3) 收藏 举报 所有程序执行的代码都是有入口的,在这里我们暂时分析一种情景,蓝牙打开着, ...

  6. for/while 循环全部执行完,, 中途不会停下!!中途不会停下!!中途不会停下!!! 中途不会停下!!!!!

    对于这样一个在for 里面的, 他会从开始到最后走走一遍,然后再回到开始, 而不是在里面有两个操作,全部操作完第一个再往下走, 这个和我的学习方法似乎一样,真的要全局来一遍,再从新来一遍回顾问题 下面 ...

  7. django 错误之 OSError: mysql_config not found

    pip 导入包时出现如下错误 Complete output from command python setup.py egg_info: /bin/: mysql_config: not found ...

  8. html5 js 游戏的一篇博客 貌似不错

    http://blog.csdn.net/lufy_legend/article/details/8888787

  9. virtualbox迁移已建虚机存储磁盘方法

    1. 先关闭虚拟机 2. 将虚拟机的磁盘拷贝或移动到想要存储的位置,virtualbox一般为.vdi文件(虚拟磁盘文件) 3. vboxmanage internalcommands sethduu ...

  10. 随手练——博弈论入门 leetcode - 486. Predict the Winner

    题目链接:https://leetcode.com/problems/predict-the-winner/ 1.暴力递归 当前数组左边界:i,右边界:j: 对于先发者来说,他能取到的最大值是:max ...