← 全部文章

ARC103F Distance Sums 题解

本文目录(3 节)
  1. 题意
  2. 题解
  3. 代码

ARC103F Distance Sums

题意

  • 有一棵 nn 个点的树。
  • 对于每个点 ii,已知 did_i,表示 ∑j=1ndist⁡(i,j)\sum_{j=1}^n \operatorname{dist}(i,j)。
  • 所有 did_i 两两互不相同。
  • 构造出一棵符合要求的树,或者判断无解。
  • n≤105n \le 10^5。

题解

首先这棵树只有一个重心,否则这两个重心的 dd 值相同,且这个重心一定是 dd 值最小的点。

以重心为根,有每个非根节点 xx 满足 dx>dfxd_x > d_{f_x},其中 fxf_x 表示 xx 的父亲。

按照 dd 值从大到小考虑每个点 uu,则相当于每次剥去一个叶子,且与 uu 相连的一定是 dd 值为 du−n+2sud_u - n + 2s_u 的点 vv,其中 sus_u 表示 uu 的子树内点的个数,需要动态维护。

重复 n−1n-1 次这个过程后即可确定这棵树的形态,最后检查一下重心的 dd 值是不是对的就可以了。

时间复杂度 O(nlog⁡n)\mathcal O(n \log n)。

代码

#define Fail print(-1), exit(0);
const int N = 1e5 + 7;
int n, p[N], s[N], f[N];
ll d[N], ans;
vi e[N];
map<ll, int> c;

void dfs(int x, int o) {
	ans += o;
	for (int y : e[x]) dfs(y, o + 1);
}

int main() {
	rd(n), rda(d, n);
	for (int i = 1; i <= n; i++) p[i] = i;
	sort(p + 1, p + n + 1, [&](int i, int j) { return d[i] < d[j]; });
	for (int i = 1; i <= n; i++) c[d[i]] = i, s[i] = 1;
	for (int i = n; i > 1; i--) {
		int u = p[i], fa;
		c.erase(d[u]);
		if (!(fa = c[d[u]-n+2*s[u]])) Fail;
		f[u] = fa, e[fa].pb(u), s[fa] += s[u];
	}
	dfs(p[1], 0);
	if (ans != d[p[1]]) Fail;
	for (int i = 1; i <= n; i++)
		if (f[i]) print(i, f[i]);
	return 0;
}

标签:构造

评论

    填写昵称即可留言。评论经站主审核后公开,请勿提交私人信息。

    正在连接评论服务…