问题分析:
-
我们先正向看这个问题。
-
当前树里点权最大的节点对于其他节点来说肯定是都能到的,然后我们统计一下有哪些点,再删掉这个点权最大的点即可,递归就能得到答案。
-
但是那样写可能比较复杂。
-
所以采用了反向的做法。
-
首先,我们把点权从小到大排序好,然后每一次都把当前点u变为与u相连的(已经枚举过的点)的根节点,从而构成一棵新树。最后节点的深度就是其答案。
-
我们考虑第二个样例。
-
我们可以用并查集维护父节点,从样例二可以看到我们加节点2的时候是加在之前与他相连的节点1在新树的父节点,节点5是直接连上节点2(因为它本来就和节点2相连)。
-
我们用vector来储存每一个节点相连的边。
-
最后dfs得到答案。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int fa[maxn];
pair<int, int> a[maxn];
vector<int> e[maxn]; //原树
vector<int> ans[maxn]; //新树
int depth[maxn]; //答案
int vis[maxn];
void dfs(int u)
{
for (int j = 0; j < ans[u].size(); j++)
{
depth[ans[u][j]] = 1 + depth[u];
dfs(ans[u][j]);
}
//求深度
}
int find(int x)
{
while (x != fa[x])
x = fa[x] = fa[fa[x]];
return x;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
vis[i] = 0;
fa[i] = i;
e[i].clear();
ans[i].clear();
}
memset(a, 0, sizeof(a));
for (int i = 1; i <= n - 1; i++)
{
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
//储存旧树
}
for (int i = 1; i <= n; i++)
{
cin >> a[i].first;
a[i].second = i;
}
sort(a + 1, a + 1 + n);
vis[a[1].second] = 1;
//代表是否已经加入到新树里面
for (int i = 2; i <= n; ++i)
{
int u = a[i].second;
for (auto &j : e[u])
{
if (!vis[j])
continue;
int v = find(j);
fa[v] = u;
ans[u].push_back(v);
}
vis[u] = 1;
}
depth[a[n].second] = 1;
dfs(a[n].second);
for (int i = 1; i <= n; i++)
{
cout << depth[i] << endl;
}
}
return 0;
}