zoukankan      html  css  js  c++  java
  • ZOJ 3949 (17th 浙大校赛 B题,树型DP)

    题目链接  The 17th Zhejiang University Programming Contest Problem B

    题意  给定一棵树,现在要加一条连接$1$(根结点)和$x$的边,求加了这条边之后,所有点到根结点的距离的和的最小值。

        输出这个最小值即可。

     

    当加的这条边为$1-x$时,$x$和$1$的中点及以下的所有点到根结点的距离都发生了变化,其他点都没有发生改变。

    现在设$ans[i]$表示当加的这条边为$1-x$时的答案,考虑答案从某个点转移到他的儿子。

    首先树型DP预处理出$ans[1]$。

    当$x$为$1$的儿子的时候,这时加的边为重边,所以$ans[x] = ans[1]$。

    在处理的时候设$c[dep]$为当前深度为$dep$的点。

    其他时候,令$x$和$1$的中点为$u$,这个时候$x$和$x$的父亲相比,以$u$为根的子树这个部分到$1$的距离要加$1$(更远了)。

    但是有一部分的点例外,那就是以$x$为根的子树,直接通过$x$到$1$,而不是通过$x$的父亲到$1$。

    所以考虑刚刚加的$1$,这一部分的值要减$2$。

    时间复杂度$O(n)$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    typedef long long LL;
    
    const int N = 2e5 + 10;
    
    int T, n;
    int sz[N], deep[N];
    int c[N];
    
    LL  f[N];
    LL  ans[N], all, ret;
    vector <int> v[N];
    
    void dfs(int x, int fa, int dep){
    	sz[x]   = 1;
    	f[x]    = 0;
    	deep[x] = dep;
    
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		dfs(u, x, dep + 1);
    		sz[x] += sz[u];
    		f[x]  += 0ll + f[u] + sz[u];
    	}
    }
    
    void solve(int x, int fa, int dep){
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		c[dep] = u;
    		if (deep[u] >= 2) ans[u] = ans[x] + sz[c[dep / 2 + 1]] - 2 * sz[u];
    		else ans[u] = ans[x];
    		solve(u, x, dep + 1);
    	}
    }
    		
    
    int main(){
    
    	scanf("%d", &T);
    
    	while (T--){
    		scanf("%d", &n);
    		rep(i, 0, n + 1) v[i].clear();
    		rep(i, 2, n){
    			int x, y;
    			scanf("%d%d", &x, &y);
    			v[x].push_back(y);
    			v[y].push_back(x);
    		}
    
    		dfs(1, 0, 0);
    		ans[1] = f[1];
    		c[0] = 0;
    
    		solve(1, 0, 1);
    
    		ret = ans[1];
    
    		rep(i, 2, n) ret = min(ret, ans[i]);
    		printf("%lld
    ", ret);
    	}
    
    
    	return 0;
    }
    

      

  • 相关阅读:
    .NET ------ 多线程的简单使用
    .NET --- 页面刷新(html 和 js两种方式)
    .NET ---- B/S的特点,不接收js赋值
    二分查找与二分答案
    c++运行程序 鼠标点击按钮 (c++)(windows)
    c++运行程序 光标隐藏与移动 (c++)(windows)
    推荐:史蒂芬霍金论天道
    LaTeX公式学习
    Markdown语法学习
    文言语言!!!(附c/c++自译)
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/8508676.html
Copyright © 2011-2022 走看看