题意:
一共 个点, 条关系,每条关系指定 与 两个点之间的树上距离,这个距离不会超过 ,保证有解。
思路:
构造题,主要就是如何限制条件,将问题简化再简化。
比赛时,主要是发现了两个性质。第一个性质是每个数只和一个数有关,和其它数字无关,因此只要把相邻数字填到正确区域就行,不用考虑数字之间的关系。
第二个性质是我们可以尝试构造一条链,然后将数字都摆在链上。
根据这两个性质 了一个构造方法,然后成功 …
回顾完比赛时的心酸,现在讲一个成功构造的方法。
仍然是构造链,但是我们考虑来构造一个长链,由于不同组合数字无关,因此我们可以构造一根长度为 的长链,比如 然后问题就变成了如何把每个数对应的数安排一个位置。
我们将所有组合之间距离从大到小排序,由于距离一定不会超过 ,因此我们只需要判断第 个组合间的距离是否等于 ,如果等于 ,就直接添到链尾,否则一定可以在链上找一个点构成一个分叉。由此,构造结束。
总结:
构造题的关键在于简化问题,而简化问题的方法在于限制条件。
而树上构造最常见的限制条件就是先构造一条长链,然后在构造链上的分叉,这种思考方式需要留意。
代码:
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a);
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define per(i,a,b) for(int i = a; i >= b; i--)
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
typedef long long ll;
typedef double db;
const int N = 2*1e5+100;
const db EPS = 1e-9;
using namespace std;
void dbg() {cout << "\n";}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
int n,pos[N],maxn;
vector<pair<int,int> > ans;
struct Node{
int a,b,v;
bool operator < (Node xx) const {
return v > xx.v;
}
}t[N];
int main()
{
scanf("%d",&n);
rep(i,1,n){
int a = 2*i, b = 2*i-1, v; scanf("%d",&v);
t[i] = {a,b,v};
}
sort(t+1,t+1+n);
int maxn = n, hp = 1;
rep(i,1,n){
while(pos[hp]) hp++;
pos[hp] = t[i].a;
if(hp+t[i].v == maxn+1){
pos[hp+t[i].v] = t[i].b;
maxn++;
}
else ans.push_back(make_pair(hp+t[i].v-1,t[i].b));
}
rep(i,1,maxn-1)
ans.push_back(make_pair(i,pos[i+1]));
for(auto &v:ans)
printf("%d %d\n",pos[v.first],v.second);
return 0;
}