zoukankan      html  css  js  c++  java
  • 「JSOI2013」哈利波特和死亡圣器

    「JSOI2013」哈利波特和死亡圣器

    传送门

    首先二分,这没什么好说的。

    然后就成了一个恒成立问题,就是说我们需要满足最坏情况下的需求。

    那么显然在最坏情况下伏地魔是不会走回头路的 因为这显然是白给

    那么我们肯定需要在所有它可能去的下一个点都设置防御。

    也就是说要对当前ta所在点的所有叶子设防。

    那么我们就可以考虑 ( ext{DP}) ,设 (dp_i) 表示在以 (i) 为根的子树中设防(注意这里不包括 (i) )还需要多少成员。

    那么转移就是:(dp_u = max{sumlimits_{fa_v = u} dp_v + son_u - mid, 0})

    其中 (son_u) 表示 (u) 的儿子个数,方程的意思就是说我们需要在 (i) 的所有孩子中设防并且要在孩子的子树里设防,显然我们不会需要负数的人(其实就是表示人多了)所以减掉 (mid) 后对 (0) 取个 (max)

    #include <cstdio>
    #define rg register
    #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
    template < class T > inline T max(T a, T b) { return a > b ? a : b; }
    template < class T > inline void read(T& s) {
        s = 0; int f = 0; char c = getchar();
        while ('0' > c || c > '9') f |= c == '-', c = getchar();
        while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
        s = f ? -s : s;
    }
     
    const int _ = 3e5 + 5;
     
    int tot, head[_]; struct Edge { int v, nxt; } edge[_ << 1];
    inline void Add_edge(int u, int v) { edge[++tot] = (Edge) { v, head[u] }, head[u] = tot; }
     
    int n, son[_], dp[_];
     
    inline void dfs(int u, int f) {
        for (rg int i = head[u]; i; i = edge[i].nxt) {
        	int v = edge[i].v; if (v == f) continue ;
        	dfs(v, u), ++son[u];
        }
    }
     
    inline void dfs(int u, int f, int mid) {
        dp[u] = son[u] - mid;
        for (rg int i = head[u]; i; i = edge[i].nxt) {
        	int v = edge[i].v; if (v == f) continue ;
        	dfs(v, u, mid), dp[u] += dp[v];
        }
        dp[u] = max(dp[u], 0);
    }
     
    inline bool check(int mid) { dfs(1, 0, mid); return dp[1] == 0; }
     
    int main() {
    #ifndef ONLINE_JUDGE
        file("cpp");
    #endif
        read(n);
        for (rg int u, v, i = 1; i < n; ++i) read(u), read(v), Add_edge(u, v), Add_edge(v, u);
        dfs(1, 0);
        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);
        return 0;
    }
    
  • 相关阅读:
    iOS:CALayer(17-12-06更)
    iOS:绘图(18-01-25更)
    iOS:动画(18-10-15更)
    iOS:文件操作相关(18-03-23更)
    iOS:SQL
    iOS开发 - OC - block的详解
    iOS开发 - Swift - 自己写的一个九宫格解锁的Demo
    关于如何使用脚本自动打包IPA文件
    iOS开发 - OC - 苹果为大家提供的后台:CloudKit 的简单使用
    iOS开发 - OC - duplicate symbol _OBJC / undefind symbol 错误的相关处理
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/12283750.html
Copyright © 2011-2022 走看看