Codeforces Round #498 (Div. 3) E. Military Problem(dfs记录)

题意:

给出一棵树,然后q个询问(u,k),每个询问代表以u为子树根,向下遍历(序号小的优先),问遍历到第k个元素是多少?如果k大于这棵子树的节点总数,那么输出-1.

思路:

首先n和q是20000的,如果每次询问都遍历一次,那么复杂度是n^2,肯定会超时。所以我们可以遍历整棵树,只遍历一次,在遍历的时候记下每个子树根的起点和终点,然后把遍历的值放在一个数组中,最后每次询问时,我们可以直接输出结果,这样时间复杂度为n。

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
int vis[200005];
int se[200005][2];//se[i][0]代表以i为子树根的起点 se[i][1]代表终点。
int ans[2000005];//保存整个树的遍历结果,也就是以1为根的深搜
vector<int>V[200005];
int kas;//代表ans数组记录到kas个了
void dfs(int k)
{
    vis[k]=1;
    se[k][0]=++kas;//记录起点
    ans[kas]=k;
    int len=V[k].size();
    for(int i=0;i<len;i++)
    {
        if(!vis[V[k][i]])
        {
            dfs(V[k][i]);
        }
    }
    se[k][1]=kas;//记录终点
    return;
}
int main()
{
    int n,q;
    while(~scanf("%d%d",&n,&q))
    {
        kas=0;
        for(int i=0;i<=n;i++)
        {
            V[i].clear();
            se[i][0]=se[i][1]=0;
            ans[i]=0;
            vis[i]=0;
        }
        int root;
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&root);
            V[root].push_back(i);
        }
        for(int i=1;i<=n;i++)
        {
            sort(V[i].begin(),V[i].end());
        }
        dfs(1);
        int u,k;
       while(q--)
       {
           scanf("%d%d",&u,&k);
           if(k>se[u][1]-se[u][0]+1)
           {
               printf("-1\n");
           }
           else
            printf("%d\n",ans[se[u][0]+k-1]);
       }
    }

}

猜你喜欢

转载自blog.csdn.net/zyy_1998/article/details/81155915