题解 P9981 [USACO23DEC] Minimum Longest Trip G

【洛谷专栏】

题意

\(N\) 个点 \(M\) 条边的有向无环图,对于每一个点 \(i\) 你需要求出一条从 \(i\) 出发的最长路径且路径上边权组成的序列字典序最小。

求每一条路径的长度和边权和。

分析

最长的路径很好求,在 DAG 上拓扑排序后动态规划即可。(具体的实现可以参考 OI-Wiki

现在的问题就变成了怎么求字典序最小。

如果朴素的进行比较判断时间复杂度在最坏情况下是 \(O(N^2)\),难以通过此题,考虑优化。

一个序列比等长的另一个序列字典序更小,当且仅当在它们不同的第一个位置,前者比后者的元素更小。

说明序列的字典序只和其中一个数有关,于是需要一个更快的方法,来找到第一个不同的位置。

类似于字符串哈希的方法,可以预处理前缀哈希使得单次查询一个子串的复杂度变成 \(O(1)\)。但是因为没有记录一条链上的所有节点所以不便于二分,考虑换成倍增。

然后是类似于最近公共祖先的倍增写法,不断的向上跳找到第一个标签值不同的位置,然后比较即可。

时间复杂度 \(O(M \log N)\),可以通过此题。

代码

//the code is from chenjh
#include<cstdio>
#include<queue>
#include<utility>
#include<vector>
#define MAXN 200002
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const unsigned int p=131;//自然溢出哈希底数。
int n,m,in[MAXN];
int tp[MAXN],c=0;
vector<PII> G[MAXN];
int f[MAXN];//最长链的长度。
LL s[MAXN];//标签和。
int fa[MAXN][19];//链上节点倍增。
ULL pn[MAXN<<2],hs[MAXN][19];//倍增哈希。
int main(){
	pn[0]=1;
	for(int i=1,mi=MAXN<<2;i<mi;i++) pn[i]=pn[i-1]*p;//预处理哈希底数的幂次。
	scanf("%d%d",&n,&m);
	for(int i=0,u,v,w;i<m;i++)
		scanf("%d%d%d",&u,&v,&w),
		G[u].emplace_back(v,w),++in[v];
	queue<int> Q;
	for(int i=1;i<=n;i++)if(!in[i]) Q.push(i);
	for(int u;!Q.empty();){//对图进行拓扑排序。
		u=Q.front(),Q.pop();
		tp[++c]=u;
		for(const auto&[v,w]:G[u])if(!--in[v]) Q.push(v);
	}
	for(int i=n,u;i>0;--i){//根据拓扑序倒推。
		u=tp[i];
		for(const auto&[v,w]:G[u])
			if(f[u]<f[v]+1||(f[u]==f[v]+1&&(ULL)w<*hs[u]))//存在更长的路径或长度相同但当前标签比答案更小就直接更新答案。
				f[u]=f[v]+1,s[u]=s[v]+w,*fa[u]=v,*hs[u]=w;
			else if(f[u]==f[v]+1&&(ULL)w==*hs[u]){//长度相同且第一位也相同,才有必要进行进一步的判断。
				int x=*fa[u],y=v;
				for(int k=18;k>=0;--k)if(fa[x][k] && fa[y][k] && hs[x][k]==hs[y][k])
					x=fa[x][k],y=fa[y][k];//向上跳找到第一个不同的点。
				if(x&&y&&*hs[y]<*hs[x])
					f[u]=f[v]+1,s[u]=s[v]+w,*fa[u]=v,*hs[u]=w;//不同的位置更小,更新答案。
			}
		for(int k=1;k<19;k++)
			fa[u][k]=fa[fa[u][k-1]][k-1],
			hs[u][k]=hs[fa[u][k-1]][k-1]*pn[1<<(k-1)]+hs[u][k-1];//倍增处理祖先和祖先的哈希。
	}
	for(int i=1;i<=n;i++) printf("%d %lld\n",f[i],s[i]);
	return 0;
}
posted @ 2024-03-31 19:18  Chen_Jinhui  阅读(94)  评论(0)    收藏  举报