1. 程式人生 > >Luogu3233 HNOI2014 世界樹 虛樹

Luogu3233 HNOI2014 世界樹 虛樹

傳送門


$\sum m \leq 300000$,老套路建虛樹進行$DP$

建好虛樹後,先用兩次$DFS$計算到達所有虛點最近的重要點$be_i$

注意這兩次$DFS$的作用:第一次是考慮兒子影響父親,第二次是考慮父親影響兒子,所以兩次$DFS$的更新和遞迴之間的順序需要搞清楚

然後考慮每一個虛點$i$會對$be_i$控制的點的數量產生多大的貢獻。

首先,在原樹上沒有重要點的子樹一定被$be_i$所控制,這個點的數量就是$size_i-\sum size_j[\text{j是i的兒子且j子樹中至少有一個重要點}]$,後面的一部分直接通過虛樹上的兒子在原樹上倍增到$i$的孩子節點計算即可。

然後考慮虛樹上的一條邊。如果這條邊兩端的$be$是相同的,那麼中間所有的點也一定被這個$be$控制,直接算入答案;否則必定存在一個分界點,其兩端分屬兩個不同的重要點控制。我們在原樹上倍增找到這個分界點然後兩邊計算答案加入貢獻即可。

  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 = 300010; 22 struct Edge{ 23 int end , upEd , w; 24 }Ed[MAXN << 1] , newEd[MAXN];
25 int head[MAXN] , s[MAXN] , newHead[MAXN] , dfn[MAXN] , belong[MAXN] , dep[MAXN] , minDis[MAXN] , size[MAXN] , jump[MAXN][20]; 26 int N , cnt , cntEd , headS , cntNewEd , ts , num[MAXN] , ans[MAXN] , output[MAXN]; 27 28 void addEd(Edge* Ed , int* head , int& cntEd , int a , int b , int c = 0){ 29 Ed[++cntEd].end = b; 30 Ed[cntEd].w = c; 31 Ed[cntEd].upEd = head[a]; 32 head[a] = cntEd; 33 } 34 35 void init(int now , int fa){ 36 dep[now] = dep[fa] + 1; 37 size[now] = 1; 38 dfn[now] = ++ts; 39 jump[now][0] = fa; 40 for(int i = 1 ; jump[now][i - 1] ; ++i) 41 jump[now][i] = jump[jump[now][i - 1]][i - 1]; 42 for(int i = head[now] ; i ; i = Ed[i].upEd) 43 if(Ed[i].end != fa){ 44 init(Ed[i].end , now); 45 size[now] += size[Ed[i].end]; 46 } 47 } 48 49 inline int jumpToLCA(int x , int y){ 50 if(dep[x] < dep[y]) 51 swap(x , y); 52 for(int i = 19 ; i >= 0 ; --i) 53 if(dep[x] - (1 << i) >= dep[y]) 54 x = jump[x][i]; 55 if(x == y) 56 return x; 57 for(int i = 19 ; i >= 0 ; --i) 58 if(jump[x][i] != jump[y][i]){ 59 x = jump[x][i]; 60 y = jump[y][i]; 61 } 62 return jump[x][0]; 63 } 64 65 void create(){ 66 minDis[1] = 0x3f3f3f3f; 67 cntNewEd = belong[1] = 0; 68 for(int i = 1 ; i <= cnt ; ++i){ 69 belong[num[i]] = num[i]; 70 minDis[num[i]] = 0; 71 } 72 for(int i = 1 ; i <= cnt ; ++i) 73 if(!headS) 74 s[++headS] = num[i]; 75 else{ 76 int t = jumpToLCA(s[headS] , num[i]); 77 if(t != s[headS]){ 78 while(dfn[s[headS - 1]] > dfn[t]){ 79 addEd(newEd , newHead , cntNewEd , s[headS - 1] , s[headS] , dep[s[headS]] - dep[s[headS - 1]]); 80 --headS; 81 } 82 addEd(newEd , newHead , cntNewEd , t , s[headS] , dep[s[headS]] - dep[t]); 83 if(s[--headS] != t) 84 s[++headS] = t; 85 } 86 s[++headS] = num[i]; 87 } 88 while(headS - 1){ 89 addEd(newEd , newHead , cntNewEd , s[headS - 1] , s[headS] , dep[s[headS]] - dep[s[headS - 1]]); 90 --headS; 91 } 92 if(s[headS] != 1) 93 addEd(newEd , newHead , cntNewEd , 1 , s[headS] , dep[s[headS]] - 1); 94 --headS; 95 } 96 97 inline int jumpToCH(int x , int y){ 98 for(int i = 19 ; i >= 0 ; --i) 99 if(dep[y] - (1 << i) > dep[x]) 100 y = jump[y][i]; 101 return y; 102 } 103 104 void dfs1(int now){ 105 for(int i = newHead[now] ; i ; i = newEd[i].upEd) 106 if(dep[newEd[i].end] > dep[now]){ 107 dfs1(newEd[i].end); 108 if(minDis[newEd[i].end] + newEd[i].w < minDis[now] || (minDis[newEd[i].end] + newEd[i].w == minDis[now] && belong[newEd[i].end] < belong[now])){ 109 minDis[now] = minDis[newEd[i].end] + newEd[i].w; 110 belong[now] = belong[newEd[i].end]; 111 } 112 } 113 } 114 115 void dfs2(int now){ 116 for(int i = newHead[now] ; i ; i = newEd[i].upEd) 117 if(dep[newEd[i].end] > dep[now]){ 118 if(minDis[now] + newEd[i].w < minDis[newEd[i].end] || (minDis[now] + newEd[i].w == minDis[newEd[i].end] && belong[now] < belong[newEd[i].end])){ 119 minDis[newEd[i].end] = minDis[now] + newEd[i].w; 120 belong[newEd[i].end] = belong[now]; 121 } 122 dfs2(newEd[i].end); 123 } 124 } 125 126 void dfs3(int now){ 127 int Size = size[now]; 128 for(int i = newHead[now] ; i ; i = newEd[i].upEd) 129 if(dep[newEd[i].end] > dep[now]){ 130 int k = newEd[i].end , t = jumpToCH(now , k); 131 dfs3(k); 132 Size -= size[t]; 133 if(belong[k] == belong[now]) 134 Size += size[t] - size[k]; 135 else{ 136 int pre = k; 137 for(int j = 19 ; j >= 0 ; --j) 138 if(dep[k] - dep[jump[pre][j]] + minDis[k] < dep[jump[pre][j]] - dep[now] + minDis[now] || (dep[k] - dep[jump[pre][j]] + minDis[k] == dep[jump[pre][j]] - dep[now] + minDis[now] && belong[k] < belong[now])) 139 pre = jump[pre][j]; 140 ans[belong[k]] += size[pre] - size[k]; 141 Size += size[t] - size[pre]; 142 } 143 belong[k] = 0; 144 minDis[k] = 0x3f3f3f3f; 145 } 146 ans[belong[now]] += Size; 147 newHead[now] = 0; 148 } 149 150 bool cmp(int a , int b){ 151 return dfn[a] < dfn[b]; 152 } 153 154 int main(){ 155 #ifndef ONLINE_JUDGE 156 freopen("3233.in" , "r" , stdin); 157 //freopen("3233.out" , "w" , stdout); 158 #endif 159 memset(minDis , 0x3f , sizeof(minDis)); 160 N = read(); 161 for(int i = 1 ; i < N ; ++i){ 162 int a = read() , b = read(); 163 addEd(Ed , head , cntEd , a , b); 164 addEd(Ed , head , cntEd , b , a); 165 } 166 init(1 , 0); 167 for(int M = read() ; M ; --M){ 168 cnt = read(); 169 for(int i = 1 ; i <= cnt ; ++i) 170 output[i] = num[i] = read(); 171 sort(num + 1 , num + cnt + 1 , cmp); 172 create(); 173 dfs1(1); 174 dfs2(1); 175 dfs3(1); 176 for(int i = 1 ; i <= cnt ; ++i){ 177 printf("%d " , ans[output[i]]); 178 ans[output[i]] = 0; 179 } 180 putchar('\n'); 181 } 182 return 0; 183 }