zoukankan      html  css  js  c++  java
  • CF613D Kingdom and its Cities

    题意:

    一个王国有n座城市,城市之间由n-1条道路相连,形成一个树结构,国王决定将一些城市设为重要城市。

    这个国家有的时候会遭受外敌入侵,重要城市由于加强了防护,一定不会被占领。而非重要城市一旦被占领,这座城市就不能通行。

    国王定了若干选择重要城市的计划,他想知道,对于每个计划,外敌至少要占领多少个非重要城市,才会导致重要城市之间两两不连通。如果外敌无论如何都不可能导致这种局面,输出-1。

    题解:

    考虑树形dp,首先考虑不行的情况,那么就是俩个相邻的点都是被标记的点,特判掉。然后fx表示以x为根的子树的答案,g[x]表示自己是否变为标记点。若x是标记点,则要让自己的儿子中有标记都选上。若x带有标记,若子节点带标记的大于等于2,则答案++。若只有一个儿子标记,那么标记保留。然后如果每次都dp的话,复杂度nq,肯定不行。考虑k的和很小,就把要用到的点,拿出来之后树形dp,这就用到了虚树的思想。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 const int N = 2e5 + 10;
      5 
      6 inline int read()
      7 {
      8     char ch = getchar();int x = 0, f = 1;
      9     while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
     10     while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) - '0' + ch; ch = getchar();}
     11     return x * f;
     12 }
     13 
     14 int n, m, k;
     15 int h[N], e[N], ne[N], idx, a[N];
     16 int size[N], son[N], top[N], d[N], f[N], dfn[N], num;
     17 int stac[N], sz, vs[N];
     18 int dp[N];
     19 vector<int>g[N];
     20 void add(int a, int b)
     21 {
     22     e[idx] = b;
     23     ne[idx] = h[a];
     24     h[a] = idx ++;
     25 }
     26 
     27 void dfs1(int u, int fa)
     28 {
     29     d[u] = d[fa] + 1;
     30     f[u] = fa;
     31     size[u] = 1;
     32     for (int i = h[u]; ~i; i = ne[i])
     33     {
     34         int j = e[i];
     35         if(j == fa) continue;
     36         dfs1(j, u);
     37         size[u] += size[j];
     38         if(size[son[u]] < size[j])
     39             son[u] = j;
     40     }
     41 }
     42 
     43 void dfs2(int u, int tp)
     44 {
     45     top[u] = tp;
     46     dfn[u] = ++ num;
     47     if(son[u]) dfs2(son[u], tp);
     48     for (int i = h[u]; ~i; i = ne[i])
     49     {
     50         int j = e[i];
     51         if(j == son[u] || j == f[u]) continue;
     52         dfs2(j, j);
     53     }
     54 }
     55 
     56 int lca(int x, int y)
     57 {
     58     while(top[x] != top[y])
     59     {
     60         if(d[top[x]] < d[top[y]]) swap(x, y);
     61         x = f[top[x]];
     62     }
     63     return d[x] < d[y] ? x : y;
     64 }
     65 
     66 bool cmp(int a, int b)
     67 {
     68     return dfn[a] < dfn[b];
     69 }
     70 
     71 int dfs(int u)
     72 {
     73     int res = 0, mn = 0;
     74     for (auto &j : g[u])
     75     {
     76         res += dfs(j);
     77         mn += dp[j];
     78     }
     79     if(vs[u]) res += mn, dp[u] = 1;
     80     else if(mn > 1) res ++, dp[u] = 0;
     81     else dp[u] = mn;
     82     g[u].clear(); vs[u] = 0;
     83     return res;
     84 }
     85 
     86 int main()
     87 {
     88     n = read();
     89     for (int i = 1; i <= n; i ++) h[i] = -1;
     90     for (int i = 1; i <= n - 1; i ++)
     91     {
     92         int a = read(), b = read();
     93         add(a, b); add(b, a);
     94     }
     95     dfs1(1, 0);dfs2(1, 1);
     96     m = read();
     97     while(m --)
     98     {
     99         int flag = 1;
    100         k = read();
    101         for (int i = 1; i <= k; i ++) a[i] = read(), vs[a[i]] = 1;
    102         for (int i = 1; i <= k; i ++)
    103             if(vs[a[i]] && vs[f[a[i]]])
    104             {
    105                 flag = 0;
    106                 break;
    107             }
    108         if(!flag)
    109         {
    110             for (int i = 1; i <= k; i ++)
    111                 vs[a[i]] = 0;
    112             puts("-1");
    113             continue;
    114         }
    115         sort(a + 1, a + k + 1, cmp);
    116         sz = 0;
    117         stac[++ sz] = a[1];
    118         for (int i = 2; i <= k; i ++)
    119         {
    120             int z = lca(stac[sz], a[i]);
    121             while(d[z] < d[stac[sz - 1]])
    122             {
    123                 g[stac[sz - 1]].push_back(stac[sz]);
    124                 sz --;
    125             }
    126             if(z != stac[sz])
    127             {
    128                 g[z].push_back(stac[sz]);
    129                 if(z == stac[sz - 1]) sz --;
    130                 else stac[sz] = z;
    131             }
    132             stac[++ sz] = a[i];
    133         }
    134         while(-- sz) g[stac[sz]].push_back(stac[sz + 1]);
    135         printf("%d
    ", dfs(stac[1]));
    136     }
    137 }
    View Code
  • 相关阅读:
    L-这是最难的题(二分+前缀和)
    SPFA 原理剖析代码实现分析比较
    树状数组---原理代码实现
    bellman-ford算法
    UML用例图总结
    UML类图几种关系的总结
    UML序列图总结
    线段树--Color the ball(多次染色问题)
    临时文档3
    POJ2676-Sudoku(数独)
  • 原文地址:https://www.cnblogs.com/xwdzuishuai/p/14076587.html
Copyright © 2011-2022 走看看