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;
    }
    
  • 相关阅读:
    OC拨打电话
    oc唯一标时一部设备
    去掉UITableView多余的分割线
    UICollectionView的使用
    设置ulabel的行间距
    uitextfield
    iOS导航栏适配
    App Store 升级问题
    mac中使用终端生成RSA私钥和公钥文件
    js document
  • 原文地址:https://www.cnblogs.com/hankeke/p/BZOJ2097.html
Copyright © 2011-2022 走看看