zoukankan      html  css  js  c++  java
  • 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_ileq10^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;
    }
    
  • 相关阅读:
    C#基础篇——泛型
    基于.NetCore3.1系列 —— 使用Swagger导出文档 (补充篇)
    基于.NetCore3.1系列 —— 使用Swagger导出文档 (番外篇)
    springboot深入浅出系列(16章97节)-看了都说好
    小书MybatisPlus第5篇-Active Record模式精讲
    小书MybatisPlus第4篇-表格分页与下拉分页查询
    使用位运算、值交换等方式反转java字符串-共四种方法
    有效提高java编程安全性的12条黄金法则
    小书MybatisPlus第3篇-自定义SQL
    结合SpEL使用@Value-基于配置文件或非配置的文件的值注入-Spring Boot
  • 原文地址:https://www.cnblogs.com/mangoyang/p/9366770.html
Copyright © 2011-2022 走看看