ARC103D Distance Sums 题解

题面

题意

注意到距离最大的点一定是叶子节点。

那么按 \(D_i\) 从大到小枚举节点,找到它的父亲 \(u\),直接加一条边。注意到这种做法是必要但不充分的,于是最后再重新跑一遍换根 dp 求出距离和判断和 \(D_i\) 是否相等即可。

具体的,假设当前节点为 \(v\),其子树大小为 \(sz_v\),它的父亲为 \(u\),那么要满足 \(D_u=D_v+sz_v-(n-sz_v)\)。二分找到 \(u\) 之后要记得更新 sz[u] += sz[v]

代码:

#include <bits/stdc++.h>
#define DC int T = gi <int> (); while (T--)
#define DEBUG fprintf(stderr, "Passing [%s] line %d\n", __FUNCTION__, __LINE__)
#define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
#define fi first
#define se second
#define pb push_back
#define mp make_pair

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, int> PLI;
typedef pair <LL, LL> PLL;

template <typename T>
inline T gi()
{
	T x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return f * x;
}

template <typename T>
inline T abs(T x) {return x < 0 ? -x : x;}

const int N = 100003, M = N << 1;

int n;
LL d[N];
int sz[N];
PLI p[N];
vector <int> g[N];
LL nd[N];
int nsz[N];

void dfs(int u, int f, int dis)
{
	nd[1] += dis, nsz[u] = 1;
	for (auto v : g[u]) if (v != f) dfs(v, u, dis + 1), nsz[u] += nsz[v];
}

void dfs1(int u, int f) {for (auto v : g[u]) if (v != f) nd[v] = nd[u] + n - 2 * nsz[v], dfs1(v, u);}

void dfs_print(int u, int f) {for (auto v : g[u]) if (v != f) printf("%d %d\n", u, v), dfs_print(v, u);}

int main()
{
	//freopen(".in", "r", stdin); freopen(".out", "w", stdout);
	n = gi <int> ();
	for (int i = 1; i <= n; i+=1) d[i] = gi <LL> (), p[i] = {d[i], i}, sz[i] = 1;
	sort(p + 1, p + 1 + n);
	for (int i = n; i > 1; i-=1)
	{
		LL tmp = p[i].fi - n + 2 * sz[p[i].se];
		int id = lower_bound(p + 1, p + 1 + n, mp(tmp, 0)) - p;
		if (p[id].fi != tmp) return puts("-1"), !!0;
		g[p[i].se].pb(p[id].se), g[p[id].se].pb(p[i].se);
		sz[p[id].se] += sz[p[i].se];
	}
	dfs(1, 0, 0);
	dfs1(1, 0);
	for (int i = 1; i <= n; i+=1) if (nd[i] != d[i]) return puts("-1"), !!0;
	dfs_print(1, 0);
	return !!0;
}

启发:

  • 造树题要想一些特殊情况,如叶子、重心等。
上一篇:二分查找的分析与应用


下一篇:将列表合计行进行合并,element-ui