Codeforces 196 C. Paint Tree

## [$>Codeforces \space 196 C. Paint Tree<$](http://codeforces.com/problemset/problem/196/C)

题目大意 : 给出 \(n\) 个点构成的一棵树,以及平面上 \(n\) 个点的坐标,现在要求出一种方案,给平面上每个点一个不同的编号,对于每个平面上的点按照编号连树边,使得最终得到的边在平面上两两不相交

$1 \leq n \leq 1500, -10^9 \leq x_i, y_i\leq10^9 $

解题思路 :

观察发现,要使得最后连接的树边不相交,对于树中相邻的儿子节点对应的子树,它们在平面上对应的区域不能相交

换句话说,对于任意一棵子树内的连边,其在平面上的向量不能于其他子树内的向量相交

那么问题就转化为给每一个子树 \(u\) 安排 \(sz_u\) 个合法的点并且满足上述条件

考虑分治来处理这个问题,每棵子树对应的区间如果在极角排序的结果上是有序且连续的,那么子树间的向量一定不会相交

所以每次选取当前区间内最左下角的点,将其作为当前子树节点根节点对应的点,并以其为基准进行极角排序

对于它的每一个儿子 \(v\),在区间内划分一段大小为 \(sz_v\) 的子区间递归处理,可以证明这样一定有解

考虑这样做最多递归 \(n\) 层,每一层要处理的区间最多大小是 \(n\), 总复杂度是 \(O(n^2logn)\)


/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
#define N (500005)
vector<int> g[N];
int sz[N], Ans[N], n;
struct Point{ double x, y; int id; } a[N], O;
inline double cross(double X1, double X2, double Y1, double Y2){
	return X1 * Y2 - X2 * Y1;
}	
inline bool cmp(Point A, Point B){
	return cross(A.x - O.x, A.y - O.y, B.x - O.x, B.y - O.y) > 0;
}
inline void dfs(int u, int fa){
	sz[u] = 1;
	for(int i = 0; i < g[u].size(); i++){
		int v = g[u][i];
		if(v != fa) dfs(v, u), sz[u] += sz[v];
	}
}
inline void solve(int u, int fa, int l, int r){
	int co = l;
	for(int i = l + 1; i <= r; i++)
		if(a[i].y < a[co].y || a[i].y == a[co].y && a[i].x < a[co].x) co = i;
	if(co != l) swap(a[co], a[l]); 
	O = a[l], Ans[a[l].id] = u;
	sort(a + l + 1, a + r + 1, cmp);
	int pos = l + 1;
	for(int i = 0; i < g[u].size(); i++){
		int v = g[u][i];
		if(v != fa) 
			solve(v, u, pos, pos + sz[v] - 1), pos += sz[v];
	}
	
}		
int main(){
	read(n);
	for(int i = 1, x, y; i < n; i++){
		read(x), read(y);
		g[x].push_back(y), g[y].push_back(x);
	}
	for(int i = 1; i <= n; i++)
		scanf("%lf%lf", &a[i].x, &a[i].y), a[i].id = i;
	dfs(1, 0), solve(1, 0, 1, n);
	for(int i = 1; i <= n; i++) printf("%d ", Ans[i]);
	return 0;
}
posted @ 2018-07-25 16:40  Joyemang33  阅读(223)  评论(0编辑  收藏  举报