首页 > 其他分享 >F. Timofey and Black-White Tree

F. Timofey and Black-White Tree

时间:2023-01-30 19:13:00浏览次数:46  
标签:dist int text Tree sqrt ans Timofey White 节点

F. Timofey and Black-White Tree

Timofey came to a famous summer school and found a tree on $n$ vertices. A tree is a connected undirected graph without cycles.

Every vertex of this tree, except $c_0$, is colored white. The vertex $c_0$ is colored black.

Timofey wants to color all the vertices of this tree in black. To do this, he performs $n - 1$ operations. During the $i$-th operation, he selects the vertex $c_i$, which is currently white, and paints it black.

Let's call the positivity of tree the minimum distance between all pairs of different black vertices in it. The distance between the vertices $v$ and $u$ is the number of edges on the path from $v$ to $u$.

After each operation, Timofey wants to know the positivity of the current tree.

Input

The first line contains the integer $t$ ($1 \le t \le 10^4$) — the number of testcases.

The first line of each testcase contains the integers $n, c_0$ ($2 \le n \le 2 \cdot 10^5$, $1 \le c_0 \le n$) — the number of vertices in the tree and index of the initial black vertex.

The second line of each testcase contains $n - 1$ unique integers $c_1, c_2, \dots, c_{n-1}$ ($1 \le c_i \le n$, $c_i \ne c_0$), where $c_i$ is the vertex which is colored black during the $i$-th operation.

Each of the next $n - 1$ row of each testcase contains the integers $v_i, u_i$ ($1 \le v_i, u_i \le n$) — edges in the tree.

It is guaranteed that the sum of $n$ for all testcases does not exceed $2 \cdot 10^5$.

Output

For each testcase, print $n - 1$ integer on a separate line.

The integer with index $i$ must be equal to positivity of the tree obtained by the first $i$ operations.

Example

input

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

output

3 2 1 1 1 
3 1 1 
3 2 2 2 2 2 1 1 1 
4 2 2 1 1 1 
5 1 1 1 1 1 1 1 
4 3 2 2 1 1 1 1 1 

Note

In the first testcase, after the second operation, the tree looks like this:

The distance between vertices $1$ and $6$ is $3$, the distance between vertices $4$ and $6$ is $3$, the distance between vertices $1$ and $4$ is $2$. The positivity of this tree is equal to the minimum of these distances. It equals $2$.

In the third testcase, after the fourth operation, the tree looks like this:

The positivity of this tree is $2$.

 

解题思路

  这题的难度感觉超过我的能力水平了,看了半天都不是很理解给出的做法,包括时间复杂度的证明也是很懵。

  不难想到暴力的做法是每染黑一个点,就从这个点开始bfs,然后枚举所有已染黑的点到这个点的最短距离,并维护一个全局的最小值,时间复杂度是$O(n^2)$。实际上给出的做法也是暴力的思路,不过在bfs的时候加了剪枝,最终的时间复杂度变成了$O(n \sqrt{n})$。

  在下面讲述的方法中$\text{dist}$数组的定义与原先的定义不同,原先bfs中$\text{dist}[v]$表示从始点(树根)到节点$v$的最小值,下面的方法中$\text{dist}[v]$表示离节点$v$最近的已被染黑的点的距离。注意这里的最近不是指最新被染黑的节点,而是所有已经染黑的节点中,距离它最近的那个节点。

  大致的流程为每染黑一个点$c_i$,把$c_i$加入队列进行bfs。在bfs的过程中假设当前的节点为$u$,与$u$相邻的节点都记作$v$,只有$\text{dist}[v] > \text{dist}[u] + 1$并且$\text{dist}[u] + 1 < \text{ans}$才更新$\text{dist}[v]$并把$v$加入队列,其中$\text{ans}$记录的是任意两个被染黑的点间的最小距离,显然$\text{ans}$只会变小不会变大。最后是答案的输出,每次遍历到$c_i$,那么就对$\text{ans}$和$\text{dist}[c_i]$取最小值,再输出$\text{ans}$(先输出答案再染黑$c_i$)。首先$\text{ans}$已经记录了之前所有被染黑的点间的最小距离,在染黑$c_i$后本质上是想知道$c_i$到其他已染黑的点最短距离,然后更新$\text{ans}$,而$\text{dist}[c_i]$就表示所有已染黑的点中距离$c_i$的最短距离,因此在染黑$c_i$前取$\text{ans} = \min\{ {\text{ans}, \text{dist}[c_i]} \}$就可以达到此目的。

  下面重点讲讲剪枝。首先是只有$\text{dist}[v] > \text{dist}[u] + 1$才更新$\text{dist}[v]$。这是很显然的,问题就是如果$v$不加入队列那么以$v$为根的子树都得不到更新。实际上这些节点都不需要更新,因为这些节点之前都是通过$\text{dist}[v]$更新得到最小距离的,如果要以$\text{dist}[u] + 1$更新距离,明显不如$\text{dist}[v]$小,因此这些节点是不会被更新的。

  然后是$\text{dist}[u] + 1 < \text{ans}$才更新$\text{dist}[v]$。首先补充一个概念,在长度为$n$的数轴中加入$\sqrt{n}$个点,那么任意两点间的最小距离所能够取到的最大值为$\sqrt{n}$(准确来说是$\sqrt{n}$这个量级),即当所有点都按照间隔$\sqrt{n}$来排列时取到。这个结论在树中也成立,在一颗$n$个节点的树中选择$\sqrt{n}$个节点,所能取到的任意两个节点的最小距离的最大值为$\sqrt{n}$量级。这个结论也是参考别人的说法,我感觉不是很显然,也许可以通过dfs序来证明,这里就默认这个结论是正确的。意味着当已经染黑了$\sqrt{n}$个节点,此时的$\text{ans}$必然不超过$\sqrt{n}$(量级)。

  因此按照上面的算法在枚举完前$\sqrt{n}$个节点时的时间复杂度为$O(n \sqrt{n})$,枚举剩下的节点的时间复杂度也是$O(n \sqrt{n})$,因此总的时间复杂度就是$O(n \sqrt{n})$。下面来分析枚举剩下的节点的时间复杂度。bfs的时间复杂度取决于所有弹出队列的节点的度数,因此可以计算在枚举剩下的节点的过程中,所有节点能够入队的次数。因为枚举完前$\sqrt{n}$个节点后,任意两个黑色节点的最短距离不超过$\sqrt{n}$,而要入队的只有白色节点,在$\text{dist}[u] + 1 < \text{ans}$才更新$\text{dist}[v]$的限制下,可以发现每个节点最多只能入队$\sqrt{n}$次,因此所有节点入队的总次数就是$O(n \sqrt{n})$的量级,因此时间复杂度也是$O(n \sqrt{n})$。

  可以发现这总做法被分成了两个部分,前部分是枚举前$\sqrt{n}$个节点,后部分是枚举剩下的节点,而这两部分的时间复杂度均为$O(n \sqrt{n})$,这种做法被称为根号分治。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 2e5 + 10, M = N * 2;
 5 
 6 int c[N];
 7 int head[N], e[M], ne[M], idx;
 8 int dist[N];
 9 int q[N], hh, tt;
10 int ans;
11 
12 void add(int v, int w) {
13     e[idx] = w, ne[idx] = head[v], head[v] = idx++;
14 }
15 
16 void bfs(int src) {
17     hh = 0, tt = -1;
18     q[++tt] = src;
19     dist[src] = 0;
20     while (hh <= tt) {
21         int t = q[hh++];
22         for (int i = head[t]; i != -1; i = ne[i]) {
23             if (dist[e[i]] > dist[t] + 1 && dist[t] + 1 < ans) {
24                 dist[e[i]] = dist[t] + 1;
25                 q[++tt] = e[i];
26             }
27         }
28     }
29 }
30 
31 void solve() {
32     int n;
33     scanf("%d", &n);
34     for (int i = 0; i < n; i++) {
35         scanf("%d", c + i);
36     }
37     idx = 0;
38     memset(head, -1, sizeof(head));
39     for (int i = 0; i < n - 1; i++) {
40         int v, w;
41         scanf("%d %d", &v, &w);
42         add(v, w), add(w, v);
43     }
44     ans = n + 1;
45     memset(dist, 0x3f, sizeof(dist));
46     for (int i = 0; i < n; i++) {
47         ans = min(ans, dist[c[i]]);
48         if (i) printf("%d ", ans);
49         bfs(c[i]);
50     }
51     printf("\n");
52 }
53 
54 int main() {
55     int t;
56     scanf("%d", &t);
57     while (t--) {
58         solve();
59     }
60     
61     return 0;
62 }

  补充个dfs实现的AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 2e5 + 10, M = N * 2;
 5 
 6 int c[N];
 7 int head[N], e[M], ne[M], idx;
 8 int dist[N];
 9 int ans;
10 
11 void add(int v, int w) {
12     e[idx] = w, ne[idx] = head[v], head[v] = idx++;
13 }
14 
15 void dfs(int u, int pre, int d) {
16     if (d >= ans) return;
17     dist[u] = d;
18     for (int i = head[u]; i != -1; i = ne[i]) {
19         if (e[i] != pre && dist[e[i]] > d + 1) dfs(e[i], u, d + 1);
20     }
21 }
22 
23 void solve() {
24     int n;
25     scanf("%d", &n);
26     for (int i = 0; i < n; i++) {
27         scanf("%d", c + i);
28     }
29     idx = 0;
30     memset(head, -1, sizeof(head));
31     for (int i = 0; i < n - 1; i++) {
32         int v, w;
33         scanf("%d %d", &v, &w);
34         add(v, w), add(w, v);
35     }
36     ans = n + 1;
37     memset(dist, 0x3f, sizeof(dist));
38     for (int i = 0; i < n; i++) {
39         ans = min(ans, dist[c[i]]);
40         if (i) printf("%d ", ans);
41         dfs(c[i], -1, 0);
42     }
43     printf("\n");
44 }
45 
46 int main() {
47     int t;
48     scanf("%d", &t);
49     while (t--) {
50         solve();
51     }
52     
53     return 0;
54 }

 

参考资料

  Codeforces Round #847 (Div. 3) Editorial:https://codeforces.com/blog/entry/111948

  Codeforces Round #847 (Div. 3) F(根号分治):https://zhuanlan.zhihu.com/p/601326343

标签:dist,int,text,Tree,sqrt,ans,Timofey,White,节点
From: https://www.cnblogs.com/onlyblues/p/17077001.html

相关文章

  • npm ERR! ERESOLVE unable to resolve dependency tree 问题解决
    阅读原文-问题解决与原因分析安装命令增加--legacy-peer-deps修饰npminstall--legacy-peer-deps......
  • Scape - Goat Tree
    目录Scape-GoatTreeBasisDefinitionPushupCheckMid-travelbuild&rebuildInsertRemoveGetrankbyvalueGetvaluebyrankGetlast&GetnextFinalCodeScape-Go......
  • 题解 CF277E【Binary Tree on Plane】
    费用流。可以将原问题转化为类似于匹配的问题,只不过这种匹配并不是一对一的。具体地,将每个点\(u\)拆成两个点\(u_\text{fa},u_\text{son}\),设源点为\(s\)、汇点为\(t......
  • Potree 004 点云点大小形状设置
    点云数据就是靠海量的点显示来模拟真实世界的。点大小设置就比较重要,例如如果数据稀疏,点显示的时候,可以设置稍微大一些。如果点数据比较密集,则可以显示小一些。在Potree中......
  • 【模板】ODT | Old Driver Tree | 珂朵莉树
    postedon2021-04-0220:38:49|under学术|source这个东西本身不常用,但是这个维护连续段的写法很常用。标签:暴力、数据结构、std::set#include<set>template<cla......
  • hexo-theme-tree
    Hexo主题Tree一个简洁的主题,主要功能是“树状导航”+“树状目录”,可选配“评论”和“阅读量”功能,支持基于搜索引擎的全站搜索。通过fancybox支持图片点击放大。......
  • python-Couldn‘t find a tree builder with the features you requested: lxml
    执行BeautifulSoup(content,features='lxml')时报错,按照网上的方法安装lxml、重新安装lxml、安装指定版本lxml,都无效。最后发现只是PyCharm设置中project的pyth......
  • 二叉树的实现-BSTree
    二叉树的实现-BSTree一、树和二叉树1-1树的定义翻译过来就是:树是由结点构成的,结点可以有也可以没有。若有结点,则肯定只有一个根结点。树是一种递归结构,俗称“套娃”......
  • 【Winform】TreeView使用汇总
    1、拖拽节点到另一个容器Panel中TreeView控件需要监听:(1)ItemDrag事件(当用户开始拖动节点时发生)。对于Panel控件:(1)开启Panel的AlowDrop属性设置为true表示允许进行拖入操......
  • 「解题报告」ARC138F KD Tree
    好题!感觉比那些写出DP然后无脑上GF数学方法硬推的题有价值。首先有个朴素的想法:设\(f_{l,r,u,d}\)表示这个矩形的方案数,那么枚举分界点转移。引用大佬的话:直......