洛谷CF1006E Military Problem

题目描述

在这个问题中你需要帮助伯兰(??我没找到有Berland这个国家)军队组织他们的指挥系统

伯兰军队中一共有n个军官。第一个官员是军队的指挥官,他并没有任何上级。其他的军官都有且只有一个直接的上级。如果一个军官a是军官b的上级,那么你也可以说军官b就是军官a的下属

如果满足下列条件,那么军官x就是军官y的下属(直接或非直接):

1.y是x的直接上级 2.x的直接上级是y的下属

举个例子,下图的官员3的下属有:5,6,7,8,9

所以,在伯兰军队的结构中,除了指挥官,其他人都是指挥官的下属

形式上的,让我们把伯兰军队看成一棵拥有n个节点的树,树的节点u就代表了军官u。根(即一号节点)就相当于指挥官

伯兰战争部门命令你对q个查询给出答案。这q个查询会以(ui,ki)的形式给出,ui代表了某个军官,ki是正整数。你需要输出,编号为ui的军官下达命令后,第ki个得知此命令的军官编号是多少,如果传达人数不足ki个,输出-1。

要处理第i个查询,想象一下ui的命令如何我下达到ui的下属。这里使用了典型的DFS(深度优先搜索)算法。

假设现在的军官是a,他要下达一个命令。a军官选择一个军官b——还没有收到这个命令的直接下属(即在树上的一个孩子)。如果有许多这样的直接下属,那么A选择编号最小的那一个。A军官向B军官发出命令。之后,B使用完全相同的方式将命令扩展到它的子树。在B完成命令后,军官A再次选择下一个直接下属(使用相同的策略)。当军官A不能选择任何还没有接到命令的直接下属时,军官A下达命令完成。

让我们看一下下面这个例子(看下面的图):

如果军官1下达了命令,军官们收到命令的顺序是:1,2,3,5,6,8,7,9,4

如果军官3下达了命令,军官们收到命令的顺序是:3,5,6,8,7,9

如果军官7下达了命令,军官们收到命令的顺序是:7,9

如果军官9下达了命令,军官们收到命令的顺序是:9

你应当分开处理这些查询。一个查询不会影响其他查询的结果。

输入格式

第一行包括两个整数n,q,表示有n个军官和q个查询(2≤n≤2×10^5,1≤q≤2×10^5)

第二行包括n-1个整数,p2、p3……pn,(1≤p

接下来的q行是q个查询每行包含两个整数(ui,ki)(1≤ui,ki≤n)ui表示开始下达命令的军官,ki表示要输出的军官编号是第几个得知命令的

输出格式

一共q行,每行包含一个整数表示第i个查询的答案:编号为ui的军官下达命令后,第ki个得知此命令的军官编号是多少,如果传达人数不足ki个,输出-1。

感谢@hicc0305 提供的翻译

输入输出样例 #1

输入 #1


9 6
1 1 1 3 5 3 5 7
3 1
1 5
3 4
7 3
1 8
1 9

输出 #1


3
6
8
-1
9
4

上代码:

#include
using namespace std;
#define endl '\n'
const int maxn=2e5+2;
int n,a[maxn],q,t,u,k;  // n为节点数,a数组存储DFS序,q为查询次数,t为DFS时间戳

// 树节点结构,包含子节点列表和DFS访问的左右边界
struct node {
    vectore;  // 存储子节点的列表
    int l,r;       // 节点在DFS序列中的左右边界
} v[maxn];

// 深度优先遍历,生成树的DFS序(欧拉序)
// x: 当前遍历的节点
void dfs(int x) {
    a[++t]=x;      // 记录DFS访问顺序到数组a中
    v[x].l=t;      // 记录节点x的左边界(首次访问时间)
    sort(v[x].e.begin(),v[x].e.end());  // 对子节点排序,保证按编号升序访问
    for(auto i:v[x].e) dfs(i);          // 递归访问所有子节点
    v[x].r=t;      // 记录节点x的右边界(最后访问时间)
}

int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);  // 加速输入输出
    cin>>n>>q;  // 输入节点数和查询次数
    
    // 构建树结构(邻接表)
    for(int i=2,x; i<=n; i++) {
        cin>>x;  // 输入节点i的父节点
        v[x].e.push_back(i);  // 将节点i添加到父节点x的子节点列表中
    }
    
    dfs(1);  // 从根节点1开始DFS遍历,生成DFS序
    
    // 处理查询
    while(q--){
        cin>>u>>k;  // 查询节点u的第k个直属子节点
        
        // 计算在DFS序中对应的位置
        int pos=v[u].l+k-1;
        
        // 判断位置是否在节点u的DFS区间内
        if(pos<=v[u].r) cout<

你可能感兴趣的:(算法,dfs,树)