题目
题意: 给定n个节点的树,以1为根。规定dfs时优先搜索编号小的点,而且给出边的顺序也按从小到大给的。给定m次询问,O(1)求出以u为树根进行dfs的第k个数。
思路: 感觉和以前打的一场abc的E有点像,但是不太会写,乱写了一个T了,然后一直思绪乱乱的,直接罚坐了,200多人过的题都不会,确实不应该。
从树根开始搜和从u开始是一样的,所以从树根搜一遍得到的序列就可以O(1)查询。那么怎么记录呢?dfs序的第i个数对应出现次序为i,u的出现次序+k-1即以u为树根进行dfs的第k个数。如果以u为树根的子树大小<k,寄,无解。
时间复杂度: O(n)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int n,m,k,T;
vector<int> va[N];
int id[N];
int a[N];
vector<int> vv;
int f[N]; //以i为根的子树的大小
int dfs(int cur)
{
vv.push_back(cur);
int cnt = 1;
for(int i=0;i<va[cur].size();++i)
{
int j = va[cur][i];
cnt += dfs(j);
}
return f[cur] = cnt;
}
void solve()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=2;i<=n;++i)
{
int x; cin>>x;
va[x].push_back(i);
}
dfs(1);
for(int i=0;i<vv.size();++i)
{
a[vv[i]] = i+1; //记录vv[i]在dfs中第几次出现
}
// for(int i=1;i<=n;++i)
// {
// cout<<i<<":"<<a[i]<<endl;
// }
while(m--)
{
int root; cin>>root>>k;
int ans = -1;
if(f[root] >= k)
{
ans = vv[a[root] + k - 1 - 1]; //对应树根出现位置+k-1即对应子树第k个出现,下标从0开始要-1.
}
cout<<ans<<"\n";
}
}
signed main(void)
{
solve();
return 0;
}