CodeForces 1006E Military Problem(DFS,树的选择性遍历)
CodeForces 1006E Military Problem(DFS,树的选择性遍历)
http://codeforces.com/contest/1006/problem/E
题意:
就是给出n,m,共n个点[1,n],m次询问。第二行给出n-1个数a[i],2<=i<=n;a[i]表示i的父亲节点是a[i]。
按照题目给构建一棵树,每次询问,找到从一个结点u开始DFS到第k个的节点编号是多少,这样的点不存在时输出-1。
思路:
如果对每个查询都DFS一次,必超时
所以必须预处理
这里用vector存边,用son[i]表示编号为i的点自身+孩子结点的总个数 ,用rk[i]表示遍历次序为i的点的编号 ,用sa[i]表示编号为i的点遍历的次序
代码如下:
#include <stdio.h> #include <string.h> #include <iostream> #include <string> #include <math.h> #include <algorithm> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #include <sstream> const int INF=0x3f3f3f3f; typedef long long LL; const int mod=1e9+7; //const double PI=acos(-1); #define Bug cout<<"---------------------"<<endl const int maxm=1e6+10; const int maxn=2e5+10; using namespace std; int n,m,u,k; vector<int>vt[maxn];//存边 int son[maxn];//son[i]表示编号为i的点自身+孩子结点的总个数 int rk[maxn];//rk[i]表示遍历次序为i的点的编号 int sa[maxn];//sa[i]表示编号为i的点遍历的次序 int cnt;//遍历次序计数器 void dfs(int num) { ++cnt; rk[cnt]=num; sa[num]=cnt; int sum=1; for(vector<int>::iterator it=vt[num].begin();it!=vt[num].end();it++) { int v=*it; dfs(v); sum+=son[v]; } son[num]=sum; } int main() { int n,m; scanf("%d %d",&n,&m); for(int i=2;i<=n;i++) { int t; scanf("%d",&t); vt[t].push_back(i); } dfs(1);//预处理 for(int i=0;i<m;i++) { scanf("%d %d",&u,&k); if(son[u]<k)//孩子数小于k printf("-1\n"); else printf("%d\n",rk[sa[u]+k-1]); } return 0; }
tip:如果没说是从那个点开始,入度为0的点就为根结点;
-