【Codeforces contest-1214 E】Petya and Construction Set【树上构造】

题意:

一共 2 n 2*n 个点, n n 条关系,每条关系指定 2 i 2*i 2 i 1 2*i-1 两个点之间的树上距离,这个距离不会超过 n n ,保证有解。 ( 1 n 1 0 5 ) (1\leq n\leq 10^5)


思路:

构造题,主要就是如何限制条件,将问题简化再简化。

比赛时,主要是发现了两个性质。第一个性质是每个数只和一个数有关,和其它数字无关,因此只要把相邻数字填到正确区域就行,不用考虑数字之间的关系。

第二个性质是我们可以尝试构造一条链,然后将数字都摆在链上。

根据这两个性质 y y yy 了一个构造方法,然后成功 w a   8 wa\ 8

回顾完比赛时的心酸,现在讲一个成功构造的方法。

仍然是构造链,但是我们考虑来构造一个长链,由于不同组合数字无关,因此我们可以构造一根长度为 n n 的长链,比如 1 3 5 7... 1、3、5、7... 然后问题就变成了如何把每个数对应的数安排一个位置。

我们将所有组合之间距离从大到小排序,由于距离一定不会超过 n n ,因此我们只需要判断第 i i 个组合间的距离是否等于 n n ,如果等于 n n ,就直接添到链尾,否则一定可以在链上找一个点构成一个分叉。由此,构造结束。


总结:

构造题的关键在于简化问题,而简化问题的方法在于限制条件。

而树上构造最常见的限制条件就是先构造一条长链,然后在构造链上的分叉,这种思考方式需要留意。


代码:

#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;
}
发布了244 篇原创文章 · 获赞 115 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/100554643
今日推荐