题目链接:http://lightoj.com/volume_showproblem.php?problem=1128
给你一颗树,树的每个节点都有一个权值,树根是节点0,权值为1,树中每个节点的权值都是大于父节点的权值的;
然后给出每个节点的父节点以及该节点的权值;有Q个询问,每个询问有两个数u和val,求u的祖先中权值>=val的最大祖先,就是离u最远的那个>=val的祖先的节点;
数的范围较大有5w个Q,1w个n,所以我们不能直接模拟,也许这1w个节点是一串下来的,那么复杂度就变成了nQ必定会TLE;
我们知道每个节点i要找祖先中>=val的一定要从根节点到i的路径上去找,所以我们可以用二分;具体看代码吧;
#include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <vector> #include <algorithm> #include <map> #include <queue> #include <stack> #include <math.h> using namespace std; #define met(a, b) memset(a, b, sizeof(a)) #define N 100053 #define INF 0x3f3f3f3f const int MOD = 1e9+7; typedef long long LL; struct node { int Index, val; node(){} node(int Index, int val) : Index(Index), val(val){} }; int v[N], n, ans[N], Time, Node[N]; vector<vector<int> >G; vector<vector<node> >Q; int Find(int val) { int L = 1, R = Time, ans = Time; while(L<=R) { int Mid = (L+R)/2; if(v[Node[Mid]] >= val) { R = Mid-1; ans = Mid; } else L = Mid+1; } return Node[ans]; } void dfs(int u) { Node[++Time] = u;///Node[i]表示从根节点0到节点i的深度; int len = Q[u].size();///在询问中 问u节点的我们可以从根节点到u节点这个路径上寻找v大于val的节点,用二分法; for(int i=0; i<len; i++) { node p = Q[u][i]; ans[p.Index] = Find(p.val);///把结果保存起来; } for(int i=0, L=G[u].size(); i<L; i++) dfs(G[u][i]); Time--;///返回上一层,深度要减; } int main() { int T, q, t = 1; scanf("%d", &T); while(T--) { met(v, 0); v[0] = 1; scanf("%d %d", &n, &q); G.clear(); G.resize(n+5); Q.clear(); Q.resize(n+5); int f, u, num; for(int i=1; i<n; i++) { scanf("%d %d", &f, &v[i]); G[f].push_back(i); } for(int i=1; i<=q; i++) { scanf("%d %d", &u, &num); Q[u].push_back(node(i, num)); } Time = 0; dfs(0); printf("Case %d: ", t++); for(int i=1; i<=q; i++) printf("%d ", ans[i]); } return 0; }