ABC 239 E - Subtree K-th Max(树+dfs)

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;
}
posted @ 2022-09-26 20:02  Vijurria  阅读(30)  评论(0编辑  收藏  举报