1. 程式人生 > 實用技巧 >CF613D Kingdom and its Cities

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\n", dfs(stac[1])); 136 } 137 }
View Code