zoukankan      html  css  js  c++  java
  • CF566C Logistical Questions(重心分治)

    CF566C Logistical Questions(重心分治)

    题目大意

    • 一棵 (n) 个节点的树,点有点权,边有边权。
    • 两点间的距离定义为两点间边权和的 (frac 32) 次方。
    • 求这棵树的带权重心。
    • (n le 2 imes 10^5)

    解题思路

    以点 i 为中心的函数 (f_i(x) = dis^{1.5}_{i o x} * w[i]),不难发现它是一个下凸函数,那么当重心为 x 时候的答案为 $ans(x) = sum_{i=1}^n f_i(x) $ 由于凸函数相加还是凸函数,因此 (ans(x)) 也是凸函数,因此从一个点出发最多只有一个方向可以使答案变的更优,如何判断,众所周知,可以用导数来表示函数的变化情况,我们可以把每个子树的导数都求出来相加,如果 (sum_{i in sons(x)}p(i) - 2 * p(j) le 0),说明 j 所在的子树有更优的答案,像点分治一样跳过去即可

    时间复杂度 (Theta(NlogN))

    带码 (点分治我总会犯奇奇怪怪的错误/kk

    const int N = 200500;
    int h[N], ne[N<<1], to[N<<1], w[N<<1], tot, P, n;
    double ans = 1e20;
    inline void add(int x, int y, int z) {
    	ne[++tot] = h[x], to[h[x] = tot] = y, w[tot] = z;
    }
    
    int siz[N], vis[N], val[N], Siz, lim, rt;
    void get_rt(int x, int fa) {
    	siz[x] = 1; int mx = 0;
    	for (int i = h[x]; i; i = ne[i]) {
    		int y = to[i]; if (y == fa || vis[y]) continue;
    		get_rt(y, x), siz[x] += siz[y]; Mx(mx, siz[y]);
    	}
    	Mx(mx, Siz - siz[x]);
    	if (mx < lim) lim = mx, rt = x;
    }
    
    double d[N], sum, sumd;
    void dfs(int x, int fa, int dis, int num) {
    	sum += pow(dis, 1.5) * val[x], d[num] += pow(dis, 0.5) * 1.5 * val[x];
    	for (int i = h[x], y; i; i = ne[i]) 
    		if ((y = to[i]) != fa) dfs(y, x, dis + w[i], num);
    }
    
    void solve(int x) {
    	if (vis[x]) return; 
    	get_rt(x, 0), vis[x] = 1, sum = sumd = 0;
    	for (int i = h[x]; i; i = ne[i]) {
    		int y = to[i]; d[y] = 0;
    		dfs(y, x, w[i], y), sumd += d[y];
    	}
    	if (sum < ans) ans = sum, P = x;
    	for (int i = h[x]; i; i = ne[i]) {
    		int y = to[i];
    		if (sumd - d[y] * 2 >= 0) continue;
    		Siz = siz[y], lim = 998224353, get_rt(y, 0);
    		solve(rt); break;
    	}
    }
    
    int main() {
    	read(n);
    	for (int i = 1;i <= n; i++) read(val[i]);
    	for (int i = 1, x, y, z; i < n ; i++) 
    		read(x), read(y), read(z), add(x, y, z), add(y, x, z);
    	Siz = n, lim = 1919810, get_rt(1, 0), solve(rt);
    	printf ("%d %.8lf
    ", P, ans);
    	return 0;
    }
    
  • 相关阅读:
    JavaScript
    Eclipse修改类的注释模板
    无法解析指定的连接标识符的解决办法
    MySQL
    IDEA修改SQL语句的关键字大写
    iframe中操作后通过后台返回脚本,让父窗口刷新
    IDEA启动Tomcat控制台打印乱码
    Eclipse如何打开文件的磁盘位置
    深度学习目标检测算法综述(论文和代码)
    关于并发,异步,非阻塞(python)疑惑的一些资料解答
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12918105.html
Copyright © 2011-2022 走看看