牛客网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\),使得 ...
随机推荐
- 用以替换系统NSLog的YouXianMingLog
用以替换系统NSLog的YouXianMingLog 这是本人自己使用并改良的用以替换系统NSLog的类,非常好用,以下是使用示例,现在开源出来并提供源码,好用的话顶一下吧^_^ 效果: YouXia ...
- php命名空间的设计思想和缺点
相比C#等语言,你可以在PHP函数里面随意定义变量并赋值,而不用担心覆盖了全局变量,或者类变量:你也可以随意的定义类变量,而不用担心会和函数名冲突,因为变量前面都有个$. php的命名空间和全局变量. ...
- PHP中抽象方法、抽象类和接口的用法
在类中,没有方法体的方法就是抽象方法. abstract 可见性 function 方法名称(参数1,.....); // 如果没有显示地指定可见性,则默认为public 如: public ...
- 深入浅出SharePoint2013——安装SharePoint2013
在这个页面的底部可以通过相应链接下载Sharepoint Server安装文件 https://technet.microsoft.com/en-us/library/cc262788.aspx
- 解决数据库自增ID的问题
(1)设置主键自增为何不可取这样的话,数据库本身是单点,不可拆库,因为id会重复. (2)依赖数据库自增机制达到全局ID唯一使用如下语句:REPLACE INTO Tickets64 (stub) V ...
- 理解活在Iphone中的那些App (二)
app是什么,为什么而存在 存在即合理的说法,已经被批臭批烂了.所以,作为一个程序员不能简简单单的因为上面来了一个需求,就完成一个需求.让做一个app就做一个app,只是简单的认为存在即合理,头让写就 ...
- 1088. [SCOI2005]扫雷Mine【网格DP】
Description 相信大家都玩过扫雷的游戏.那是在一个n*m的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了 ,“余”人国流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子 ...
- 配置网卡绑卡 --RHEL7
配置网卡绑卡 1)网卡绑定(team方式) # 创建组接口nmcli connection add type team ifname team0 con-name team0 config '{&qu ...
- [luogu1080] 国王游戏
题面 这是一个比较经典(害人不浅)的题目啊, 很早就听说过这个题目的大名, 今日得见, 果然非凡题所可以比拟的啊, 行了, 瞎扯就先扯到这里, 题目大意应该是很好解释的, 我就不解释了, 要使得最 ...
- ddt Ui 案例2
准备用例文件:testcase1.py testcase2.py import ddt import unittest from HTMLTestRunner import HTMLTestRunne ...