https://atcoder.jp/contests/abc239/tasks/abc239_e
题目大意:
给定一棵树,根节点是1,一共有n个节点,每一个节点都有它自己的值
给定n-1条边,和q个询问
问我们在第x个节点之下的叶子节点中,值排第k大的是什么?输出它的值。
Sample Input 1
5 2
1 2 3 4 5
1 4
2 1
2 5
3 2
1 2
2 1
Sample Output 1
4
5
Sample Input 2
6 2
10 10 10 9 8 8
1 4
2 1
2 5
3 2
6 4
1 4
2 2
Sample Output 2
9
10
Sample Input 3
4 4
1 10 100 1000
1 2
2 3
3 4
1 4
2 3
3 2
4 1
Sample Output 3
1
10
100
1000
这道题目有一个很关键的点就在于k不会超过20,所以我们对于每个节点,只需要保存它的子树中价值排名20前的就行了
这样就可以保证一定在数据范围之内
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;
const LL N=200200,M=2002;
LL n,q,a[N];
vector<LL> g[N],f[N];
//g表示存储的节点,f表示存储的前20大的值
bool cmp(LL l,LL r)
{
return l>r;
}
void dfs(LL u,LL fa)
{
//进去了首先把这个节点下的自己的值加进来
f[u].push_back(a[u]);
//爆搜一遍这个节点下所拥有的子节点
for(int i=0;i<g[u].size();i++)
{
int t=g[u][i];
if(t==fa) continue;//不能回去搜父节点,不然就死循环了
dfs(t,u);//找到了,继续往下深搜
for(LL x:f[t])//将递归回来的数加入父节点的集合
f[u].push_back(x);
}
sort(f[u].begin(),f[u].end(),cmp);//给当前节点排个序
while(f[u].size()>20)//超过20个的就不要
f[u].pop_back();
}
int main()
{
cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
int T=1;
//cin>>T;
while(T--)
{
cin>>n>>q;
//记录每个点的值
for(LL i=1;i<=n;i++)
cin>>a[i];
//建立边
for(LL i=1;i<=n-1;i++)
{
LL u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,-1);//从根节点开始爆搜,它的父节点是-1
while(q--)
{
LL x,k;
cin>>x>>k;
//这里输出的是值,而非节点(f)
cout<<f[x][k-1]<<endl;
}
}
return 0;
}
标签:10,ABC,Max,LL,Subtree,dfs,back,Sample,节点
From: https://www.cnblogs.com/Vivian-0918/p/16732210.html