zoukankan      html  css  js  c++  java
  • BZOJ2097 [Usaco2010 Dec]Exercise 奶牛健美操 贪心

    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=2097

    题解

    显然二分一个 (mid) 表示每一块的直径长度的最大值,求最少需要多少连通块。

    然后我们发现如果一个合法连通块的直径没有经过这个连通块的顶点,那么在顶点上加边时,这个连通块的直径就可以忽略了,因为无论如何都无法使得这个原来的直径边长了。因此只需要考虑从顶点向下的最长链就可以了。

    于是我们记录一个 (f[i]) 表示以 (i) 为根的连通块的最长链的长度。然后贪心,从子树合并到根的时候,我们将所有的 (f[son]) 排序,然后找到最大满足相邻的两个合并起来小于等于 (mid) 的。后面的就全部需要割掉了。


    代码如下,由于需要排序,时间复杂度 (O(nlog n))

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I>
    inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 1e5 + 7;
    
    int n, m, cnt;
    int tt[N], f[N];
    
    struct Edge { int to, ne; } g[N << 1]; int head[N], tot;
    inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
    inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }
    
    inline void dfs(int x, const int &mid, int fa = 0) {
    	for fec(i, x, y) if (y != fa) dfs(y, mid, x);
    	tt[0] = 0, f[x] = 0;
    	for fec(i, x, y) if (y != fa) tt[++tt[0]] = f[y] + 1;
    	std::sort(tt + 1, tt + tt[0] + 1);
    	for (int i = tt[0]; i; --i)
    		if ((i == 1 && tt[i] <= mid) || tt[i] + tt[i - 1] <= mid) {
    			f[x] = tt[i];
    			break;
    		} else ++cnt;
    }
    
    inline bool check(const int &mid) {
    	cnt = 0;
    	dfs(1, mid);
    	return cnt <= m;
    }
    
    inline void work() {
    	int l = 0, r = n - 1;
    	while (l < r) {
    		int mid = (l + r) >> 1;
    		if (check(mid)) r = mid;
    		else l = mid + 1;
    	}
    	printf("%d
    ", l);
    }
    
    inline void init() {
    	read(n), read(m);
    	for (int i = 1; i < n; ++i) {
    		int x, y;
    		read(x), read(y);
    		adde(x, y);
    	}
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    Git撤销commit消息保留修改
    switchysharp设置
    Windows10下的docker安装与入门 (三) 创建自己的docker镜像并且在容器中运行它
    Windows10下的docker安装与入门 (二)使用docker引擎在容器中运行镜像
    Windows10下的docker安装与入门 (一)使用docker toolbox安装docker
    semver(Semantic Versioning)
    conda install mingw libpython
    下载 安装MYsql 服务器
    .NET(c#) 移动APP开发平台
    .NET(c#) 移动APP开发平台
  • 原文地址:https://www.cnblogs.com/hankeke/p/BZOJ2097.html
Copyright © 2011-2022 走看看