题意:
n n n个点的树,每个点有一个不一样的点权,求从每个点出发能到达的点数(需满足终点为起点到终点路径上的最大点权才能到达) T < 1 e 4 , n < 1 e 5 , ∑ n < 8 e 5 。 T < 1e4, n < 1e5, \sum{n} < 8e5。 T<1e4,n<1e5,∑n<8e5。
思路:
可以考虑点权最大的那个结点
x
x
x,显然其他所有点都能到达它,且到达它之后不能越过它到其他的点去。
所以节点
x
x
x一定是最优方案中最后一个到达的点,所以我们可以把这个点
x
x
x去掉,再对剩下的独立联通块重复操作。
因为在递归过程中很难实现每次去节点的操作,所以可以按照去掉点的顺序建立一棵新的树,每个节点的深度就是答案。
#include<bits/stdc++.h>
#define maxn 100086
using namespace std;
int t,n,f[maxn],x,y;
int val[maxn],vis[maxn],ans[maxn];
vector<int>v1[maxn],v2[maxn];
map<int,int>mp;
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void dfs(int u){
for(int i:v2[u]){
ans[i]=ans[u]+1;
dfs(i);
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
v1[x].push_back(y);
v1[y].push_back(x);
}
mp.clear();
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
mp[val[i]]=i;
f[i]=i;
}
vis[mp.begin()->second]=1;
for(auto i=++mp.begin();i!=mp.end();i++){
int u=i->second;
for(int v:v1[u]){
if(!vis[v])continue;
int to=find(v);
f[to]=find(u);
v2[u].push_back(to);
}
vis[u]=1;
}
int u=(--mp.end())->second;
ans[u]=1;
dfs(u);
for(int i=1;i<=n;i++){printf("%d\n",ans[i]);vis[i]=0;}
for(int i = 1; i <= n; i++)v1[i].clear(), v2[i].clear();
}
return 0;
}
死磕一下午最后都没做出来的我是屑