# CF871E Restore the Tree

## 题目大意

yzh 有一棵 $$n$$ 个节点的妹子树。大给给 ztr 对 yzh 使用了男♂酮♂魔♂法，导致 yzh 把妹子树忘记了！

## 本题题解

$$\mathrm{dis}(u, v)$$ 表示 $$u, v$$ 两点的树上距离。

## 参考代码

#include <bits/stdc++.h>
using namespace std;

void impossible() {
puts("-1");
exit(0);
}

int main() {
int n, k;
assert(scanf("%d %d", &n, &k) == 2);
assert(k > 0);

vector <int> dist[k];
vector <int> idx(n, 0);

for (int i = 0; i < k; ++i) {
dist[i] = vector <int> (n, 0);
for (int j = 0; j < n; ++j)
assert(scanf("%d", &dist[i][j]) == 1);

idx[i] = -1;
for (int j = 0; j < n; ++j)	{
if (dist[i][j] == 0) {
if (idx[i] != -1)
impossible();
else
idx[i] = j;
}
}

if (idx[i] == -1)
impossible();

for (int j = 0; j < i; ++j)
if (idx[i] == idx[j])
impossible();
}

vector <int> p(n, -1);
vector <int> h = dist[0];
int root = idx[0];

vector <int> ps[k];
for (int i = 0; i < k; ++i)
ps[i] = vector <int> ();

for (int t = 1; t < k; ++t) {
int v = idx[t];
vector <int> &d = dist[t];

vector <int> pars(n, -1);
for (int u = 0; u < n; ++u) {
if (h[u] + d[u] == h[v]) {
if (pars[h[u]] != -1)
impossible();
pars[h[u]] = u;
}
}

for (int i = 0; i < n; ++i) {
if (pars[i] == -1 && i <= h[v])
impossible();
if (pars[i] != -1 && i > h[v])
impossible();
}

for (int i = 0; i < h[v]; ++i) {
int pu = pars[i];
int u = pars[i + 1];
if (p[u] != -1 && p[u] != pu)
impossible();
p[u] = pu;
}

ps[t] = pars;
}

if (p[root] != -1)
impossible();

vector <int> subs[n];
for (int i = 0; i < n; ++i)
subs[i] = vector <int> ();

vector <int> vh[n];
for (int i = 0; i < n; ++i)
vh[i] = vector <int> ();
for (int v = 0; v < n; ++v)
vh[h[v]].push_back(v);

for (int hh = 0; hh < n; ++hh) {
for (int v: vh[hh]) {
if (v == root || p[v] != -1)
continue;

int lp = root;
int lt = 0;

for (int t = 1; t < k; ++t) {
int u = idx[t];
vector <int> &d = dist[t];
vector <int> &pars = ps[t];

// h[v] + h[u] - 2 * h[l] == d[v]
// 2 * h[l] == h[v] + h[u] - d[v]

int hl2 = h[v] + h[u] - d[v];
if (hl2 % 2 != 0)
impossible();

int hl = hl2 / 2;
if (hl < 0 || hl > h[u] || hl > h[v])
impossible();

int l = pars[hl];
if (h[l] >= h[lp]) {
if (pars[h[lp]] != lp)
impossible();
lp = l;
lt = t;
} else {
if (ps[lt][h[l]] != l)
impossible();
}
}

subs[lp].push_back(v);
}
}

for (int i = 0; i < n; ++i) {
int prev = i;
int nxt = -1;
for (int v: subs[i]) {
assert(prev != -1);
if (h[v] == h[prev] + 1) {
p[v] = prev;
nxt = v;
} else {
prev = nxt;
if (prev != -1 && h[v] == h[prev] + 1) {
p[v] = prev;
nxt = v;
} else
impossible();
}
}
}

for (int i = 0; i < n; ++i) {
if (i == root)
assert(p[i] == -1);
else {
printf("%d %d\n", i + 1, p[i] + 1);
}
}

return 0;
}

posted @ 2021-03-15 13:09  duyiblue  阅读(239)  评论(2编辑  收藏  举报