原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=4366
题意: 给你一棵树,每个结点有两个属性值,1:能力值 2:忠诚度
然后m个询问,每次询问一个整数u,求u的子树中能力值大于u的且忠诚度最大的点的编号
思路:首先如果不考虑能力值的要求,只考虑求忠诚度的要求,然后又因为这是在树上的,所以我们可以将树进行DFS转化为DFS序,这样之后就是求在某一区间上的区间最值,,很明显这是可利用线段树去做的.但是现在的限制谈条件又多了一个.那么我们就考虑将所有的能力值按从大到小排序,这样子,我们每次查询的都是能力比当前大的节点,就满足题目要求了.
#include <bits/stdc++.h>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 5e4 + 5;
const int mod = 998244353;
int t, n, m, cnt;
int ans[maxn];
map<int, int>mp;//因为题目说了忠诚值全都不一样,所以可以映射
vector<int>G[maxn];
void init() {
cnt = 0;
CLR(ans, -1);
mp.clear();
for (int i = 0; i <= n; i++) G[i].clear();
}
void add_edge(int u, int v) {
G[u].push_back(v);
}
int st[maxn], en[maxn];
void dfs(int u) {//dfs序
st[u] = cnt++; //第一次出现
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
dfs(v);
}
en[u] = cnt;//记得放外面
}
int id, MAX[maxn << 2]; //MAX能力值
void push_up(int rt) {
MAX[rt] = max(MAX[rt << 1], MAX[rt << 1 | 1]);
}
void build(int l, int r, int rt) {//建树
MAX[rt] = -1;
if (l == r) {
return ;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
push_up(rt);
}
void updata(int p, int val, int l, int r, int rt) {//单点更新
if (l == r) {
MAX[rt] = val;
return ;
}
int mid = (l + r) >> 1;
if (mid >= p) updata(p, val, lson);
else updata(p, val, rson);
push_up(rt);
}
int query(int L, int R, int l, int r, int rt) { //查询区间最大值
if (L > R) return -1;
if (L <= l && R >= r) {
return MAX[rt];
}
int mid = (l + r) >> 1;
int res = -1;
if (mid >= L) res = max(res, query(L, R, lson));
if (mid < R) res = max(res, query(L, R, rson));
return res;
}
struct info {
int id, loy, abi;
} e[maxn];
bool cmp(info a, info b) {
return a.abi > b.abi;
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
init();
for (int i = 1; i <= n - 1; i++) {
scanf("%d%d%d", &id, &e[i].loy, &e[i].abi);
add_edge(id, i);
e[i].id = i;
mp[e[i].loy] = i;
}
sort(e + 1, e + n, cmp);
dfs(0);
build(0, n - 1, 1);
for (int i = 1, j; i < n; i = j) {
j = i;
while (j < n && e[i].abi == e[j].abi) {
int id = e[j].id;
int x = query(st[id] + 1, en[id] - 1, 0, n - 1, 1);
//+1 -1 是因为查询区间是以id为根的子树
if (x != -1) ans[id] = mp[x];
j++;
}
j = i;
while (j < n && e[i].abi == e[j].abi) {
int id = e[j].id;
updata(st[id], e[j].loy, 0, n - 1, 1);
j++;
}
}
for (int i = 1; i <= m; i++) {
int x;
scanf("%d", &x);
printf("%d\n",ans[x]);
}
}
return 0;
}