BZOJ 3611: [Heoi2014]大工程

3611: [Heoi2014]大工程

Time Limit: 60 Sec  Memory Limit: 512 MB
Submit: 1101  Solved: 478
[Submit][Status][Discuss]

Description

国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。 
我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。 
在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。
 现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。
现在对于每个计划,我们想知道:
 1.这些新通道的代价和
 2.这些新通道中代价最小的是多少 
3.这些新通道中代价最大的是多少
 

Input

第一行 n 表示点数。

 接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。
点从 1 开始标号。 接下来一行 q 表示计划数。
对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。
 第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。
 

Output

输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。 

 

Sample Input

10
2 1
3 2
4 1
5 2
6 4
7 5
8 6
9 7
10 9
5
2
5 4
2
10 4
2
5 2
2
6 1
2
6 1

Sample Output

3 3 3
6 6 6
1 1 1
2 2 2
2 2 2

HINT

n<=1000000 


q<=50000并且保证所有k之和<=2*n 

Source

[Submit][Status][Discuss]

建出虚树,树形DP

  1 #include <bits/stdc++.h>
  2 
  3 namespace scanner
  4 {
  5     inline char nextChar(void)
  6     {
  7         static const int siz = 1 << 20;
  8         
  9         static char buf[siz];
 10         static char *hd = buf + siz;
 11         static char *tl = buf + siz;
 12         
 13         if (hd == tl)
 14             fread(hd = buf, 1, siz, stdin);
 15         
 16         return *hd++;
 17     }
 18     
 19     inline int nextInt(void)
 20     {
 21         register int ret = 0;
 22         register bool neg = false;
 23         register char bit = nextChar();
 24         
 25         for (; bit < 48; bit = nextChar())
 26             if (bit == '-')neg ^= true;
 27         
 28         for (; bit > 47; bit = nextChar())
 29             ret = ret * 10 + bit - '0';
 30         
 31         return neg ? -ret : ret;
 32     }
 33 }
 34 
 35 const int inf = 1e9;
 36 
 37 const int maxn = 2000005;
 38 const int maxm = 5000005;
 39 
 40 struct graph
 41 {
 42     int hd[maxn], to[maxm], nt[maxm], tot;
 43     
 44     inline graph(void)
 45     {
 46         tot = top = 0;
 47         memset(hd, 0, sizeof(hd));
 48         memset(marked, 0, sizeof(marked));
 49     }
 50     
 51     inline void addEdge(int x, int y)
 52     {
 53         nt[++tot] = hd[x]; to[tot] = y; hd[x] = tot;
 54         nt[++tot] = hd[y]; to[tot] = x; hd[y] = tot;
 55         
 56         markPoint(x);
 57         markPoint(y);
 58     }
 59     
 60     int used[maxn], marked[maxn], top;
 61     
 62     inline void markPoint(int t)
 63     {
 64         if (!marked[t])used[++top] = t, marked[t] = true;
 65     }
 66     
 67     inline void recovery(void)
 68     {
 69         while (top)
 70         {
 71             int t = used[top--];
 72             marked[t] = false;
 73             hd[t] = 0;
 74         }
 75     }
 76 };
 77 
 78 struct boolean
 79 {
 80     bool s[maxn];
 81     
 82     inline boolean(void)
 83     {
 84         top = 0;
 85         memset(s, 0, sizeof(s));
 86         memset(marked, 0, sizeof(marked));
 87     }
 88     
 89     inline void mark(int t)
 90     {
 91         s[t] = true;
 92         
 93         markPoint(t);
 94     }
 95     
 96     int used[maxn], marked[maxn], top;
 97     
 98     inline void markPoint(int t)
 99     {
100         if (!marked[t])used[++top] = t, marked[t] = true;
101     }
102     
103     inline void recovery(void)
104     {
105         while (top)
106         {
107             int t = used[top--];
108             marked[t] = false;
109             s[t] = false;
110         }
111     }
112     
113     inline bool operator [] (int t)
114     {
115         return s[t];
116     }
117 };
118 
119 int n, m;
120 
121 graph src;
122 graph use;
123 
124 int dfn[maxn], dep[maxn], fa[maxn][21];
125 
126 void preworkDfs(graph &g, int u, int f)
127 {
128     static int tim = 0;
129     
130     dfn[u] = ++tim;
131     dep[u] = dep[f] + 1;
132     
133     fa[u][0] = f;
134     
135     for (int i = 1; i <= 20; ++i)
136         fa[u][i] = fa[fa[u][i - 1]][i - 1];
137     
138     for (int i = g.hd[u]; i; i = g.nt[i])
139         if (f != g.to[i])preworkDfs(g, g.to[i], u);
140 }
141 
142 inline int getLca(int a, int b)
143 {
144     if (dep[a] < dep[b])
145         a ^= b ^= a ^= b;
146     
147     for (int i = 20; ~i; --i)
148         if (dep[fa[a][i]] >= dep[b])
149             a = fa[a][i];
150     
151     if (a == b)return a;
152     
153     for (int i = 20; ~i; --i)
154         if (fa[a][i] != fa[b][i])
155             a = fa[a][i],
156             b = fa[b][i];
157     
158     return fa[a][0];
159 }
160 
161 inline bool cmpDfn(int a, int b)
162 {
163     return dfn[a] < dfn[b];
164 }
165 
166 boolean mrk;
167 
168 struct stack
169 {
170     int s[maxn], tot;
171     
172     inline void push(int t)
173     {
174         s[++tot] = t;
175     }
176     
177     inline void pop(void)
178     {
179         if (tot)--tot;
180     }
181     
182     inline int top(void)
183     {
184         return s[tot];
185     }
186     
187     inline int tat(void)
188     {
189         return s[tot - 1];
190     }
191     
192     inline int size(void)
193     {
194         return tot;
195     }
196     
197     inline bool empty(void)
198     {
199         return tot == 0;
200     }
201     
202     inline void clear(void)
203     {
204         tot = 0;
205     }
206 };
207 
208 stack stk;
209 
210 typedef long long lnt;
211 
212 struct answer
213 {
214     int maxi;
215     int mini;
216     
217     inline void setup(void)
218     {
219         maxi = 0;
220         mini = inf;
221     }
222     
223     inline void updateMin(int t)
224     {
225         if (mini > t)
226             mini = t;
227     }
228     
229     inline void updateMax(int t)
230     {
231         if (maxi < t)
232             maxi = t;
233     }
234 }ans;
235 
236 lnt all, dp[maxn], sz[maxn];
237 
238 int maxPath[maxn];
239 int minPath[maxn];
240 
241 void getansDfs(graph &g, int u, int f)
242 {
243     dp[u] = 0LL;
244     sz[u] = mrk[u];
245     maxPath[u] = 0;
246     minPath[u] = inf;
247     
248     for (int i = g.hd[u]; i; i = g.nt[i])
249         if (g.to[i] != f)
250         {
251             int v = g.to[i];
252             int d = dep[v] - dep[u];
253             
254             getansDfs(g, v, u);
255             
256             sz[u] += sz[v];
257             dp[u] += dp[v];
258             dp[u] += sz[v] * (all - sz[v]) * d;
259             
260             ans.updateMin(minPath[v] + minPath[u] + d);
261             ans.updateMax(maxPath[v] + maxPath[u] + d);
262             
263             if (minPath[u] > minPath[v] + d)
264                 minPath[u] = minPath[v] + d;
265             
266             if (maxPath[u] < maxPath[v] + d)
267                 maxPath[u] = maxPath[v] + d;
268         }
269     
270     if (mrk[u])
271     {
272         ans.updateMin(minPath[u]);
273         ans.updateMax(maxPath[u]);
274         
275         minPath[u] = 0;
276     }
277 }
278 
279 signed main(void)
280 {
281     n = scanner::nextInt();
282     
283     for (int i = 1; i < n; ++i)
284     {
285         int x = scanner::nextInt();
286         int y = scanner::nextInt();
287         
288         src.addEdge(x, y);
289     }
290     
291     preworkDfs(src, 1, 0);
292     
293     m = scanner::nextInt();
294     
295     while (m--)
296     {
297         static int k, p[maxn];
298         
299         k = scanner::nextInt();
300         
301         for (int i = 1; i <= k; ++i)
302             p[i] = scanner::nextInt();
303         
304         std::sort(p + 1, p + k + 1, cmpDfn);
305         
306         use.recovery();
307         mrk.recovery();
308         
309         ans.setup();
310         stk.clear();
311         
312         all = k;
313         
314         for (int i = 1; i <= k; ++i)
315             mrk.mark(p[i]);
316         
317         for (int i = 1; i <= k; ++i)
318         {
319             if (!stk.empty())
320             {
321                 int t = getLca(p[i], stk.top());
322                 
323                 while (dfn[t] < dfn[stk.top()])
324                 {
325                     if (dfn[t] >= dfn[stk.tat()])
326                     {
327                         use.addEdge(t, stk.top()), stk.pop();
328                         
329                         if (stk.top() != t)
330                             stk.push(t);
331                         
332                         break;
333                     }
334                     
335                     use.addEdge(stk.top(), stk.tat()), stk.pop();
336                 }
337             }
338                 
339             stk.push(p[i]);
340         }
341         
342         while (stk.size() > 1)
343             use.addEdge(stk.top(), stk.tat()), stk.pop();
344         
345         getansDfs(use, stk.top(), 0);
346         
347         printf("%lld %d %d
", dp[stk.top()], ans.mini, ans.maxi);
348     }
349 }

@Author: YouSiki

原文地址:https://www.cnblogs.com/yousiki/p/6298480.html