1. 程式人生 > >CF613D Kingdom and its Cities 虛樹

CF613D Kingdom and its Cities 虛樹

傳送門


 

$\sum k \leq 100000$虛樹套路題

設$f_{i,0/1}$表示處理完$i$以及其所在子樹的問題,且處理完後$i$點存在$0/1$個沒有被封住的關鍵點時的最小代價,轉移考慮$i$是否是關鍵點,隨便轉就行了

  1 #include<bits/stdc++.h>
  2 //This code is written by Itst
  3 using namespace std;
  4 
  5 inline int read(){
  6     int a = 0;
  7     bool f = 0;
  8     char c = getchar();
9 while(c != EOF && !isdigit(c)){ 10 if(c == '-') 11 f = 1; 12 c = getchar(); 13 } 14 while(c != EOF && isdigit(c)){ 15 a = (a << 3) + (a << 1) + (c ^ '0'); 16 c = getchar(); 17 } 18 return f ? -a : a;
19 } 20 21 const int MAXN = 100010; 22 struct Edge{ 23 int end , upEd; 24 }Ed[MAXN << 1] , newEd[MAXN]; 25 int head[MAXN] , jump[MAXN][20] , newHead[MAXN] , s[MAXN] , dfn[MAXN] , num[MAXN] , dp[MAXN][2] , dep[MAXN]; 26 int N , headS , cntEd , cntNewEd , ts , cnt; 27 bool imp[MAXN]; 28
29 inline void addEd(Edge* Ed , int* head , int& cntEd , int a , int b){ 30 Ed[++cntEd].end = b; 31 Ed[cntEd].upEd = head[a]; 32 head[a] = cntEd; 33 } 34 35 void init(int now , int fa){ 36 dfn[now] = ++ts; 37 dep[now] = dep[fa] + 1; 38 jump[now][0] = fa; 39 for(int i = 1 ; jump[now][i - 1] ; ++i) 40 jump[now][i] = jump[jump[now][i - 1]][i - 1]; 41 for(int i = head[now] ; i ; i = Ed[i].upEd) 42 if(Ed[i].end != fa) 43 init(Ed[i].end , now); 44 } 45 46 inline int jumpToLCA(int x , int y){ 47 if(dep[x] < dep[y]) 48 swap(x , y); 49 for(int i = 19 ; i >= 0 ; --i) 50 if(dep[x] - (1 << i) >= dep[y]) 51 x = jump[x][i]; 52 if(x == y) 53 return x; 54 for(int i = 19 ; i >= 0 ; --i) 55 if(jump[x][i] != jump[y][i]){ 56 x = jump[x][i]; 57 y = jump[y][i]; 58 } 59 return jump[x][0]; 60 } 61 62 inline void create(){ 63 imp[1] = 0; 64 dp[1][0] = dp[1][1] = 0; 65 for(int i = 1 ; i <= cnt ; ++i){ 66 imp[num[i]] = 1; 67 dp[num[i]][1] = 0; 68 dp[num[i]][0] = N + 1; 69 } 70 for(int i = 1 ; i <= cnt ; ++i) 71 if(!headS) 72 s[++headS] = num[i]; 73 else{ 74 int t = jumpToLCA(s[headS] , num[i]); 75 if(t != s[headS]){ 76 while(dep[s[headS - 1]] > dep[t]){ 77 addEd(newEd , newHead , cntNewEd , s[headS - 1] , s[headS]); 78 --headS; 79 } 80 addEd(newEd , newHead , cntNewEd , t , s[headS]); 81 if(s[--headS] != t) 82 s[++headS] = t; 83 } 84 s[++headS] = num[i]; 85 } 86 while(headS - 1){ 87 addEd(newEd , newHead , cntNewEd , s[headS - 1] , s[headS]); 88 --headS; 89 } 90 if(s[headS] != 1) 91 addEd(newEd , newHead , cntNewEd , 1 , s[headS]); 92 --headS; 93 } 94 95 void dfs(int now){ 96 int sum = 0; 97 for(int i = newHead[now] ; i ; i = newEd[i].upEd){ 98 int t = newEd[i].end; 99 dfs(t); 100 if(imp[now]) 101 if(jump[t][0] == now) 102 dp[now][1] += dp[t][0]; 103 else 104 dp[now][1] += min(dp[t][0] , dp[t][1] + 1); 105 else{ 106 if(jump[t][0] == now) 107 dp[now][1] = min(sum + dp[t][1] , dp[now][1] + dp[t][0]); 108 else 109 dp[now][1] = min(sum + dp[t][1] , dp[now][1] + min(dp[t][0] , dp[t][1] + 1)); 110 if(jump[t][0] == now) 111 sum += dp[t][0]; 112 else 113 sum += min(dp[t][0] , dp[t][1] + 1); 114 } 115 if(dp[now][1] > N) 116 dp[now][1] = N + 1; 117 if(sum > N + 1) 118 sum = N + 1; 119 } 120 sum = 0; 121 for(int i = newHead[now] ; i ; i = newEd[i].upEd){ 122 int t = newEd[i].end; 123 if(!imp[now]){ 124 sum += min(dp[t][0] , dp[t][1]); 125 dp[now][0] += dp[t][0]; 126 } 127 dp[t][0] = dp[t][1] = imp[t] = 0; 128 } 129 if(!imp[now]) 130 dp[now][0] = min(dp[now][0] , sum + 1); 131 newHead[now] = 0; 132 } 133 134 bool cmp(int a , int b){ 135 return dfn[a] < dfn[b]; 136 } 137 138 int main(){ 139 #ifndef ONLINE_JUDGE 140 freopen("613D.in" , "r" , stdin); 141 //freopen("613D.out" , "w" , stdout); 142 #endif 143 N = read(); 144 for(int i = 1 ; i < N ; ++i){ 145 int a = read() , b = read(); 146 addEd(Ed , head , cntEd , a , b); 147 addEd(Ed , head , cntEd , b , a); 148 } 149 init(1 , 0); 150 for(int M = read() ; M ; --M){ 151 cnt = read(); 152 for(int i = 1 ; i <= cnt ; ++i) 153 num[i] = read(); 154 sort(num + 1 , num + cnt + 1 , cmp); 155 create(); 156 dfs(1); 157 int t = min(dp[1][0] , dp[1][1]); 158 printf("%d\n" , t == N + 1 ? -1 : t); 159 } 160 return 0; 161 }