• P4183 [USACO18JAN]Cow at Large P


    题目链接

    要考虑子树不要光顾着想对于一个叶子的情况啊!!

    暴力

    考虑贝西所在节点固定时怎么做。我们以贝西为根节点,如果某个农夫能从叶节点迅速控制某个子树的根节点,那么这棵子树就只用一个农夫,否则是其儿子的农夫数之和。用式子表示就是:设 (f_x) 表示 (x) 子树所需要农夫的最少数量,(g_x) 表示能到达 (x) 的最近叶节点的距离,那么有:

    [f_x = 1,dep_x ge g_x ]

    [f_x = sum_yf_y,dep_x < g_x ]

    树形DP即可。复杂度 (O(n^2))

    正解

    考虑如何优化暴力。感觉不是很好优化的样子。我们不去管 (f_x) 具体是多少了,我们只去管最终能对答案贡献 1 的子树。我们发现 (dep_x ge g_x) 这个条件有个特点,满足这个条件的一定是一棵棵子树。因此我们可以在子树的顶点上把这个 1 加上。

    发现还是不好做。考虑树形差分(好像叫这个),一棵子树(整棵树除外)的点的度数的和为 (2siz - 1),即:

    [sum_{i}d_i = 2siz - 1 ]

    移项:

    [sum_{i}2 - d_i = 1 ]

    这样,如果每个点的贡献是 (2 - d_i) 的话,整棵子树的贡献就是 1.(神奇)

    这样,问题就转化为了:

    [ans_p = sum_{x}(2 - d_x)[dis(x,p) ge g_x] ]

    发现这个可以看作点对 ((x, p)) 之间的关系,因此可以点分治做。加在 (g_x - dep_x),查 (le dep_p) 的贡献和。

    关键代码:

    int d[N];
    int g[N];
    void dfs_dp(int cur, int faa) {
      if (d[cur] == 1)  g[cur] = 0;
      else  g[cur] = n;
      for (register int i = head[cur]; i; i = e[i].nxt) {
        int to = e[i].to; if (to == faa)  continue;
        dfs_dp(to, cur); MIN(g[cur], g[to] + 1);
      }
    }
    void dp_dfs(int cur, int faa) {
      for (register int i = head[cur]; i; i = e[i].nxt) {
        int to = e[i].to; if (to == faa)  continue;
        MIN(g[to], g[cur] + 1); dp_dfs(to, cur);
      }
    }
    
    int siz[N], Siz, mxSiz, root;
    bool vis[N];
    void find_root(int cur, int faa)
    uint ans[N];
    void dfs_calc(int cur, int faa, int nwd) {
      ans[cur] += query(nwd);
      for (register int i = head[cur]; i; i = e[i].nxt) {
        int to = e[i].to; if (to == faa || vis[to]) continue;
        dfs_calc(to, cur, nwd + 1);
      }
    }
    void dfs_add(int cur, int faa, int nwd) {
      add(g[cur] - nwd, 2 - d[cur]);
      for (register int i = head[cur]; i; i = e[i].nxt) {
        int to = e[i].to; if (to == faa || vis[to]) continue;
        dfs_add(to, cur, nwd + 1);
      }
    }
    void dfs_del(int cur, int faa, int nwd) {
      del(g[cur] - nwd);
      for (register int i = head[cur]; i; i = e[i].nxt) {
        int to = e[i].to; if (to == faa || vis[to]) continue;
        dfs_del(to, cur, nwd + 1);
      }
    }
    
    int stk[N], stop;
    void dfs(int cur) {
      for (register int i = head[cur]; i; i = e[i].nxt) {
        int to = e[i].to; if (vis[to])  continue;
        dfs_calc(to, cur, 1);
        dfs_add(to, cur, 1); stk[++stop] = to;
      }
      ans[cur] += query(0);
      dfs_del(cur, 0, 0);
      add(g[cur], 2 - d[cur]);
      for (register int i = stop; i; --i) {
        int to = stk[i]; dfs_calc(to, cur, 1); dfs_add(to, cur, 1);
      }
      stop = 0;
      dfs_del(cur, 0, 0);
      vis[cur] = true;
      for (register int i= head[cur]; i; i = e[i].nxt) {
        int to = e[i].to; if (vis[to])  continue;
        Siz = siz[to], mxSiz = n;
        find_root(to, cur);
        dfs(root);
      }
    }
    
    int main() {
      read(n); nn = n + n;
      for (register int i = 1; i < n; ++i) {
        int u, v; read(u), read(v);
        addedge(u, v), addedge(v, u);
        ++d[u]; ++d[v];
      }
      dfs_dp(1, 0); dp_dfs(1, 0);
      Siz = mxSiz = n;
      find_root(1, 0);
      dfs(root);
      for (register int i = 1; i <= n; ++i) {
        if (d[i] == 1)  ans[i] = 1;
        Print(ans[i]);
      }
      return 0;
    }
    
  • 相关阅读:
    Azure HDInsight 现已在中国正式发布
    避免由于Windows Update自动安装安全补丁导致VM意外重启
    如何修复在Microsoft Azure中“虚拟机防火墙打开,关闭RDP的连接端口”问题
    关于Azure Auto Scale的高级属性配置
    在Azure中使用Load Runner测试TCP最大并发连接数
    Windows Azure案例分析: 选择虚拟机或云服务?
    Windows Server基础架构云参考架构:硬件之上的设计
    浅析基于微软SQL Server 2012 Parallel Data Warehouse的大数据解决方案
    在Windows Azure公有云环境部署企业应用
    如何在后台运行_Linux_命令并且将进程脱离终端
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13586937.html
Copyright © 2020-2023  润新知