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 }

猜你喜欢

转载自www.cnblogs.com/Itst/p/10080948.html