抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

题目传送门

题意

构造一个 \(2n-1\) 个节点的树,满足 \(\forall i\in [1,n] : dis(2i-1,2i)=d_i\)\(dis(x,y)\) 表示树上 \(x\)\(y\) 的距离,\(d_i\) 是给定的。

\(n\le 10^5\)

题解

\(d_i\) 从大到小排序,然后依次把所有奇数连成一条链(按对应的 \(d_i\) 从大到小的顺序)。

然后依次考虑链上每个点对应的偶数点的位置。假设这个点是链上第 \(k\) 个点,对应的 \(d_i\) 记为 \(D\),那么显然只要把这个偶数点挂在链上第 \(k+D-1\) 个点下面即可。要注意的是,如果第 \(k+D-1\) 个点是链上最后一个点,那么再挂一个点要把链进行“扩充”。可以证明,在处理第 \(k\) 个点时,链上一定存在 \(k+D-1\) 个点(根据 \(d_i\) 从大到小进行证明)。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstdio>
#include <cctype>
#include <algorithm>
int read(){
register int x = 0;
register char ch = getchar(), f = 1;
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = !f;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ '0');
return f ? x : -x;
}
int n, cnt, id[100005];
std :: pair<int, int> d[100005];
int main(){
n = read();
for (register int i = 1; i <= n; ++i) d[i].first = -read(), d[i].second = i;
std :: sort(d + 1, d + 1 + n);
for (register int i = 1; i <= n; ++i){
if (i < n) printf("%d %d\n", 2 * d[i].second - 1, 2 * d[i + 1].second - 1);
int x = i - d[i].first - 1;
if (x <= n) printf("%d %d\n", 2 * d[x].second - 1, 2 * d[i].second);
else printf("%d %d\n", id[x - n], 2 * d[i].second);
if (x - n == cnt) id[++cnt] = 2 * d[i].second;
}
}

评论