VEXOBEN
Vexoben
Jul 7, 2018
It takes 4 minutes to read this article.

题目链接:http://codeforces.com/contest/196/problem/C

题意

给定一棵 n 个节点的树和坐标平面上的 n 个点,要求将 n 个点用 n-1 条线段连接起来形成树的结构,树边不能相交,且形成的树要和原树同构,输出方案。

数据满足任意三点不共线。

n<=1500 坐标绝对值<=1e9

题解

解一定存在且可由下述方法构造:

1、找到平面上最靠左的一个点,把它作为根;

2、将其余所有点极角排序;

3、假设根节点有一棵大小为 x 的子树,将前 x 个节点划分为一个子树,并将其中最靠左的点作为根,向下递归。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1505;

int n,m,E;
int fir[N],arr[N<<1],nex[N<<1],siz[N],ans[N];
vector<int> son[N];
struct Vector {
	int x,y,num;
}p[N],st;
vector<Vector> vec;

LL cross(Vector a,Vector b) {
	return 1LL*a.x*b.y-1LL*a.y*b.x;
}

Vector operator - (Vector a,Vector b) {
	return (Vector) {a.x-b.x,a.y-b.y,0};
}

void Add_Edge(int x,int y) {
	nex[++E]=fir[x];
	fir[x]=E; arr[E]=y;
}

void dfs(int x) {
	siz[x]=1;
	for (int i=fir[x];i;i=nex[i]) {
		if (siz[arr[i]]) continue;
		dfs(arr[i]);
		siz[x]+=siz[arr[i]];
		son[x].push_back(arr[i]);
	}
}

bool cmp1(Vector a,Vector b) {
	if (a.x!=b.x) return a.x<b.x;
	else return a.y<b.y;
}

bool cmp2(Vector a,Vector b) {
	return (cross(a-st,b-st)>0);
}

void Solve(int x,vector<Vector> vec) {
	ans[vec[0].num]=x;
	st=vec[0];
	sort(vec.begin()+1,vec.end(),cmp2);
	vector<Vector> tmp;
	int now=1;
	for (int i=0;i<son[x].size();i++) {
		tmp.clear();
		while (tmp.size()<siz[son[x][i]]) {
			tmp.push_back(vec[now]); now++;
		}
		Solve(son[x][i],tmp);
	}
}

int main() {
	scanf("%d",&n);
	for (int i=1;i<n;i++) {
		int x,y; scanf("%d%d",&x,&y);
		Add_Edge(x,y); Add_Edge(y,x);
	}
	dfs(1);
	for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y),p[i].num=i;
	sort(p+1,p+n+1,cmp1);
	for (int i=1;i<=n;i++) vec.push_back(p[i]);
	Solve(1,vec);
	for (int i=1;i<=n;i++) printf("%d ",ans[i]);
	puts("");
	return 0;
}