题意:每个人都有一个上司,每个人都有能力值和忠诚值,0是老板,现在给出m个询问,每次询问给出一个x,要求你找到x的所有直系和非直系下属中能力比他高的最忠诚的人是谁
思路:因为树上查询很麻烦,所以我们直接dfs序把关系变成线性。然后我们再分块,把每个块按照能力值升序排列,这样我们就能直接二分查找这个块内能力值大于x的数就是二分出来的数到块末尾的所有数。但是怎么查找最忠诚的?我们直接预处理每个块内i位置到块末尾的最忠诚人的位置就行了。
代码:
#include<set> #include<map> #include<stack> #include<cmath> #include<queue> #include<vector> #include<string> #include<cstdio> #include<cstring> #include<sstream> #include<iostream> #include<algorithm> typedef long long ll; using namespace std; const int maxn = 50000 + 10; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; struct node{ int name, loyalty, ability; bool operator < (const node &x) const{ return ability < x.ability; } }p[maxn]; int loyalty[maxn], ability[maxn]; int in[maxn], out[maxn]; //在dfs序列中的位置1-id int belong[maxn], id; int head[maxn], tot; struct Edge{ int to, next; }edge[maxn]; void init(){ tot = id = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v){ edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } void dfs(int u){ in[u] = ++id; p[id].ability = ability[u], p[id].loyalty = loyalty[u], p[id].name = u; for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].to; dfs(v); } out[u] = id; } int MaxLoy[maxn]; //从位置j到所属块末尾的最大loyalty的人在dfs序列的位置 int n, m, block, sz; int solve(int x){ int l = belong[in[x]], r = belong[out[x]]; int L, R; int MaxLoyalty = -1, ans = -1; L = block * (l - 1) + 1, R = min(L + block - 1, id); for(int i = L; i <= R; i++){ if(in[p[i].name] > in[x] && out[p[i].name] <= out[x]){ if(p[i].loyalty > MaxLoyalty && p[i].ability > ability[x]){ MaxLoyalty = p[i].loyalty; ans = p[i].name; } } } L = l + 1, R = r - 1; node c; c.ability = ability[x]; for(int i = L; i <= R; i++){ int s = block * (i - 1) + 1, e = s + block; int pos = upper_bound(p + s, p + e, c) - p; if(pos >= e) continue; int tmp = MaxLoy[pos]; if(p[tmp].loyalty > MaxLoyalty){ MaxLoyalty = p[tmp].loyalty; ans = p[tmp].name; } } L = block * (r - 1) + 1, R = min(L + block - 1, id); for(int i = L; i <= R; i++){ if(in[p[i].name] > in[x] && out[p[i].name] <= out[x]){ if(p[i].loyalty > MaxLoyalty && p[i].ability > ability[x]){ MaxLoyalty = p[i].loyalty; ans = p[i].name; } } } return ans; } int main(){ int T; scanf("%d", &T); while(T--){ init(); int a; scanf("%d%d", &n, &m); ability[0] = -1, loyalty[0] = -1; for(int i = 1; i <= n - 1; i++){ scanf("%d%d%d", &a, &loyalty[i], &ability[i]); addEdge(a, i); } dfs(0); block = (int)sqrt(id * 1.0); for(int i = 1; i <= id; i++){ belong[i] = (i - 1) / block + 1; } sz = belong[id]; for(int i = 1; i <= sz; i++){ int s = block * (i - 1) + 1, e = min(s + block, id + 1); sort(p + s, p + e); int Max = -1, pos; for(int j = e - 1; j >= s; j--){ if(Max < p[j].loyalty){ Max = p[j].loyalty; pos = j; } MaxLoy[j] = pos; } } while(m--){ scanf("%d", &a); printf("%d ", solve(a)); } } return 0; }