Live2D

Solution -「AGC 029E」「AT 4504」Wandering TKHS

Description

  Link.

  给一棵 n 个点的树,从某个点出发,遍历时必须走到已经走过的连通块所邻接的编号最小的结点。求从每个点出发,走到 1 号结点所需额外走的结点(即走到块的大小 1)。

  n2×105

Solution

  把 1 提为根,那么一个点到根最大的阻碍就是路径上编号最大的结点。记 mxu 表示 1u 的最大结点编号,并令 R(u,l) 表示从 u 出发,向其子树,仅经过编号严格小于 l 的点能够到达的点的个数(u 一定产生贡献,所以至少为 1),DP 状态 f(u) 表示 u 的答案。

  现令 uv 的父亲,考虑 uv 的转移。

  • mxv=v,显然 u 不会往 v 走,所以要加上 R(v,mxu)

  • 否则若 mxu=uv 就会比 u 多在子树内卡一会儿。即 R(v,u)[v<mxfau]R(v,mxfau),后一项是减去重复的贡献。

  最后,加上 u1 的贡献 f(u)

  可以用暴搜加上记忆化直接计算 R(u,l)。考虑到搜索时会被子树内一些比 l 大的结点所拦截,那么被遍历的连通块就不满足需要计算 R 的转移限制。所以遍历到的总点数 O(n)。故复杂度 O(n)

Code

#include <map>
#include <cstdio>

typedef std::pair<int, int> pii;

const int MAXN = 2e5;
int n, ecnt, head[MAXN + 5], fa[MAXN + 5], mx[MAXN + 5], ans[MAXN + 5];
std::map<pii, int> rch;

struct Edge { int to, nxt; } graph[MAXN * 2 + 5];

inline int max_ ( const int a, const int b ) { return a < b ? b : a; }

inline void link ( const int s, const int t ) {
	graph[++ ecnt] = { t, head[s] };
	head[s] = ecnt;
}

inline void init ( const int u ) {
	mx[u] = max_ ( u, mx[fa[u]] );
	for ( int i = head[u], v; i; i = graph[i].nxt ) {
		if ( ( v = graph[i].to ) ^ fa[u] ) {
			fa[v] = u, init ( v );
		}
	}
}

inline int reach ( const int u, const int lim ) {
	pii sta ( u, lim );
	if ( rch.count ( sta ) ) return rch[sta];
	int ret = 1;
	for ( int i = head[u], v; i; i = graph[i].nxt ) {
		if ( ( v = graph[i].to ) ^ fa[u] && v < lim ) {
			ret += reach ( v, lim );
		}
	}
	return rch[sta] = ret;
}

inline void solve ( const int u ) {
	for ( int i = head[u], v; i; i = graph[i].nxt ) {
		if ( ( v = graph[i].to ) ^ fa[u] ) {
			if ( mx[v] == v ) ans[v] = reach ( v, mx[u] );
			else if ( mx[u] == u ) {
				ans[v] = reach ( v, u ) - ( v > mx[fa[u]] ? 0 : reach ( v, mx[fa[u]] ) );
			}
			ans[v] += ans[u];
			solve ( v );
		}
	}
}

int main () {
	scanf ( "%d", &n );
	for ( int i = 1, u, v; i < n; ++ i ) {
		scanf ( "%d %d", &u, &v );
		link ( u, v ), link ( v, u );
	}
	init ( 1 );
	solve ( 1 );
	for ( int i = 2; i <= n; ++ i ) printf ( "%d%c", ans[i], i ^ n ? ' ' : '\n' );
	return 0;
}
posted @   Rainybunny  阅读(132)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示