2018 ICPC青岛网络赛 B. Red Black Tree(倍增lca好题)

Posted taozi1115402474

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018 ICPC青岛网络赛 B. Red Black Tree(倍增lca好题)相关的知识,希望对你有一定的参考价值。

BaoBao has just found a rooted tree with n vertices and (n-1) weighted edges in his backyard. Among the vertices, of them are red, while the others are black. The root of the tree is vertex 1 and it‘s a red vertex.
Let‘s define the cost of a red vertex to be 0, and the cost of a black vertex to be the distance between this vertex and its nearest red ancestor.

Recall that

  • The length of a path on the tree is the sum of the weights of the edges in this path.

  • The distance between two vertices is the length of the shortest path on the tree to go from one vertex to the other.

  • Vertex is the ancestor of vertex v  if it lies on the shortest path between vertex and the root of the tree (which is vertex 1 in this problem).

As BaoBao is bored, he decides to play q games with the tree. For the i-th game, BaoBao will select ki vertices v1,1,vi,2,...,vi,ki on the tree and try to minimize the maximum cost of these ki vertices by changing at most one vertex on the tree to a red vertex.

Note that

  • BaoBao is free to change any n vertex among all the vertices to a red vertex, NOT necessary among the ki  vertiecs whose maximum cost he tries to minimize.

  • All the q games are independent. That is to say, the tree BaoBao plays with in each game is always the initial given tree, NOT the tree modified during the last game by changing at most one vertex.

Please help BaoBao calculate the smallest possible maximum cost of the given ki vertices in each game after changing at most one vertex to a red vertex.

Input

There are multiple test cases. The first line of the input is an integer T, indicating the number of test cases. For each test case:

The first line contains three integers n,m and q (2≤m≤n≤105,1≤q≤2×105), indicating the size of the tree, the number of red vertices and the number of games.

The second line contains m  integers r1,r2,...,rm (1=r1<r2<...<rm≤n), indicating the red vertices.

The following (n-1)  lines each contains three integers ui,vi and wi (1≤ui,vi≤n,1≤wi≤109 ), indicating an edge with wi weight connecting vertex ui and vi  in the tree.

For the following q  lines, the i-th line will first contain an integer ki(1≤ki≤n). Then ki  integers vi,1,vi,2,...viki  follow (1≤vi,1<vi,2<...<viki≤n), indicating the vertices whose maximum cost BaoBao has to minimize.

It‘s guaranteed that the sum of in all test cases will not exceed , and the sum of in all test cases will not exceed .

Output

For each test case output q  lines each containing one integer, indicating the smallest possible maximum cost of the ki vertices given in each game after changing at most one vertex in the tree to a red vertex.

Sample Input

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

Sample Output

4
5
3
8
0
0
0

Hint

技术分享图片

The first sample test case is shown above. Let‘s denote C(v) as the cost of vertex v .

For the 1st game, the best choice is to make vertex 2 red, so that C(3)=4,C(7)=3 and C(8)=4. So the answer is 4.

For the 2nd game, the best choice is to make vertex 3 red, so that C(4)=3,C(5)=2,C(7)=4 and C(8)=5. So the answer is 5.

For the 3rd game, the best choice is to make vertex 6 red, so that C(7)=1,C(8)=2,C(10)=2 and C(11)=3. So the answer is 3.

For the 4th game, the best choice is to make vertex 12 red, so that C(4)=8,C(5)=7 and C(12)=0. So the answer is 8.

Due to the design restrictions of ZOJ, we can only provide a subset of the testing data here (the original data is too large for ZOJ to store). We will update the testing data once we update ZOJ. Sorry for the inconvenience caused.

题意

给出一棵树,其中某些点是红色,其余点是黑色。定义一个点的花费为这个点到距其最近的红色祖先节点的距离。q次查询,每次查询给出k个节点,允许将最多一个黑色点变为红色, 求这k个点中最大花费的最小值。每次查询相互独立,不影响树的初始结构。

题解

dfs处理出每个点距离1点的距离D,每个点距离红色祖先的距离dis

倍增lca预处理,用于查询公共祖先

每个查询q

先将k个点按dis从大到小排序

每次处理第i个节点

1.找到和前一个点的公共祖先

2.如果深度<上一个深度,说明然红的点在上面,需要把前面的最大值+这一段距离

3.然后当前节点本身的dis和把公共祖先染红的新距离取最小

4.2,3操作得到的值取max

5.4操作得到的max和下一个点的dis取max再整体取min,因为有可能节点操作后值变小了,使得最大值为下一个节点

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define fi first
 5 #define se second
 6 #define LL long long
 7 
 8 const int maxn=1e5+5;
 9 const int INF=0x3f3f3f3f;
10 
11 int R[maxn],cnt[maxn],fa[maxn][20],deep[maxn],n,m;
12 LL D[maxn],dis[maxn];
13 bool red[maxn];
14 vector< pair<int,int> >G[maxn];
15 
16 void dfs(int x,int f)
17 {
18     if(red[x])R[x]=x;
19     else R[x]=R[f];
20     dis[x]=D[x]-D[R[x]];
21     for(auto v:G[x])
22     {
23         if(v.fi==f)continue;
24         D[v.fi]=D[x]+v.se;
25         deep[v.fi]=deep[x]+1;
26         fa[v.fi][0]=x;
27         dfs(v.fi,x);
28     }
29 }
30 bool cmp(LL a,LL b)
31 {
32     return dis[a]>dis[b];
33 }
34 void RMQ()
35 {
36     for(int j=1;(1<<j)<=n;j++)
37         for(int i=1;i<=n;i++)
38             fa[i][j]=fa[fa[i][j-1]][j-1];
39 }
40 int LCA(int u,int v)
41 {
42     if(deep[u]<deep[v])swap(u,v);
43     int de=log(deep[u])/log(2.0);
44     for(int i=de;i>=0;i--)
45         if(deep[u]-(1<<i)>=deep[v])
46             u=fa[u][i];
47     if(v==u)return u;
48     for(int i=de;i>=0;i--)
49         if(fa[u][i]!=fa[v][i])
50             u=fa[u][i],v=fa[v][i];
51     return fa[v][0];
52 }
53 int main()
54 {    
55     int t,q,a,b,c,k;
56     scanf("%d",&t);
57     while(t--)
58     {
59         scanf("%d%d%d",&n,&m,&q);
60         for(int i=1;i<=n;i++)
61             red[i]=0,G[i].clear();
62         for(int i=1;i<=m;i++)
63             scanf("%d",&a),red[a]=1;
64         for(int i=1;i<n;i++)
65         {
66             scanf("%d%d%d",&a,&b,&c);
67             G[a].push_back(make_pair(b,c));
68             G[b].push_back(make_pair(a,c));
69         }
70         D[1]=dis[1]=dis[n+1]=0;
71         dfs(1,0);
72         RMQ();
73         while(q--)
74         {
75             scanf("%d",&k);
76             LL ans=0,maxx=0,lon;
77             for(int i=0;i<k;i++)
78                 scanf("%d",&cnt[i]);
79             cnt[k]=n+1;
80             sort(cnt,cnt+k,cmp);
81             int far=cnt[0];
82             ans=min(dis[cnt[0]],dis[cnt[1]]);
83             for(int i=1;i<k;i++)
84             {
85                 int mom=LCA(far,cnt[i]);//找上一个和当前的公共祖先,染红mom节点
86                 if(deep[mom]<deep[far])maxx+=D[far]-D[mom];//如果新祖先深度<上一个祖先深度,最大的距离需要+两个祖先之间的距离
87                 lon=min(dis[cnt[i]],D[cnt[i]]-D[mom]);//当前节点本身距离红色祖先的距离和把到mom染红后的节点距离取min
88                 maxx=max(lon,maxx);
89                 far=mom;
90                 ans=min(ans,max(maxx,dis[cnt[i+1]]));//保证每次处理最大值
91             }
92             printf("%lld
",ans);
93         }
94     }
95     return 0; 
96 }

 














以上是关于2018 ICPC青岛网络赛 B. Red Black Tree(倍增lca好题)的主要内容,如果未能解决你的问题,请参考以下文章

ACM-ICPC 2018青岛网络赛-H题

ACM-ICPC 2018青岛网络赛-A题 Saving Tang Monk II

ACM-ICPC2018 青岛赛区网络预赛-B- Red Black Tree

2018ICPC青岛现场赛 重现训练

HDU 5884 Sort -2016 ICPC 青岛赛区网络赛

2018 青岛ICPC区域赛E ZOJ 4062 Plants vs. Zombie(二分答案)