题意:给一个树,树上每个节点都有两个属性:忠诚度和能力,给出若干查询,求每个子树中能力 > 树根能力的点中,忠诚度最高的那个
思路:子树dfs序即可,然后忠诚度排个序,取能力值大于u且忠诚度最高的,虽然线段树也可以搞,练练分块。
代码:
#pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #include <vector> #include <map> #include <cstring> #include <algorithm> using namespace std; typedef long long Long; const int MAGIC = 250; const int MAX_N = 50007; struct staff { int loyalty, ability; }; bool operator < (staff a,staff b) { return a.ability < b.ability; } vector<int> adj[MAX_N]; staff arr[MAX_N], list[MAX_N], sorted[MAX_N]; int pos[MAX_N], maxl[MAX_N], size[MAX_N]; map<int,int> rev; int tot, n, q; int dfs(int u) { pos[u] = tot; list[tot] = sorted[tot] = arr[u]; tot++; int ret = 1; for (int i = 0; i < adj[u].size(); i++) { ret += dfs(adj[u][i]); } return size[pos[u]] = ret; } int work(int l,int r,int val) { if (sorted[r].ability <= val) return -1; if (sorted[l].ability > val) return maxl[l]; while (l + 1 < r) { int mid = (l + r) >> 1; if (sorted[mid].ability > val) r = mid; else l = mid; } return maxl[r]; } int main() { int T; scanf("%d",&T); while (T--) { scanf("%d%d",&n, &q); for (int i = 0; i < n; i++) { adj[i].clear(); arr[i].loyalty = arr[i].ability = -1; sorted[i] = list[i] = arr[i]; } memset(size, 0, sizeof size); memset(maxl, 0, sizeof maxl); memset(pos, 0, sizeof pos); rev.clear(); rev[-1] = -1; for (int i = 1; i < n; i++) { int fa,l,a; scanf("%d%d%d",&fa,&l,&a); adj[fa].push_back(i); rev[arr[i].loyalty = l] = i; arr[i].ability = a; } tot = 0; dfs(0); for (int i = 0; i < n; i += MAGIC) { int j = i + MAGIC; if (j > n) break; sort(sorted + i, sorted + j); maxl[j - 1] = sorted[j - 1].loyalty; for (int k = j - 2; k >= i; k--) maxl[k] = max(maxl[k + 1], sorted[k].loyalty); } while (q--) { int st; scanf("%d",&st); int val = arr[st].ability; st = pos[st]; int ed = st + size[st] - 1; int ans = -1; for (int i = st; i <= ed;) { if (i % MAGIC == 0 && i + MAGIC - 1 <= ed) { int tmp = work(i, i + MAGIC - 1, val); if (tmp > ans) ans = tmp; i += MAGIC; } else { if (list[i].ability > val && list[i].loyalty > ans) ans = list[i].loyalty; i++; } } printf("%d\n",rev[ans]); } } return 0; }
时间: 2024-10-28 10:11:09