P3605 [USACO17JAN]Promotion Counting晋升者计数
题目:传送门
ps:方法较多,主席树,树状数组,线段树合并(感觉统计子树的某些信息很好用)
线段树合并:对每个节点建一颗线段树(实际上是一条长度为lg(n)的链),然后自底向上合并。
inline void upd(int &x, int y) { x > y && (x = y); } const int N = 100005; int n, tot, cnt; int sum[20 * N], ls[20 * N], rs[20 * N], root[N], head[N], a[N], ans[N]; struct node { int to, next; } e[2 * N]; vector<int> id; inline int getId(int x) { return lower_bound(Range(id), x) - id.begin(); } void Inite() { cnt = tot = 0; mem(head, -1); } void addedge(int u, int v) { e[tot].to = v, e[tot].next = head[u], head[u] = tot++; } void Pushup(int rt) { sum[rt] = sum[ls[rt]] + sum[rs[rt]]; } void Build(int l, int r, int &rt, int pos) { if (!rt) rt = ++cnt; if (l == r) { sum[rt]++; return; } int mid = (l + r) >> 1; if (pos <= mid) Build(l, mid, ls[rt], pos); else Build(mid + 1, r, rs[rt], pos); Pushup(rt); } int Merge(int x, int y) { if (!x || !y) return x ^ y; ls[x] = Merge(ls[x], ls[y]); rs[x] = Merge(rs[x], rs[y]); Pushup(x); return x; } int Query(int l, int r, int rt, int L, int R) { if (l > R || r < L || L > R) return 0; if (L <= l && r <= R) return sum[rt]; int ans = 0; int mid = (l + r) >> 1; ans += Query(l, mid, ls[rt], L, R); ans += Query(mid + 1, r, rs[rt], L, R); return ans; } void DFS(int u) { for (int i = head[u]; ~i; i = e[i].next) { DFS(e[i].to); root[u] = Merge(root[u], root[e[i].to]); } ans[u] = Query(1, n, root[u], getId(a[u]) + 2, n); } int main() { sc(n); Rep(i, 1, n) sc(a[i]), id.pb(a[i]); sort(Range(id)); Rep(i, 1, n) Build(1, n, root[i], getId(a[i]) + 1); Inite(); rep(i, 1, n) { int x; sc(x); addedge(x, i + 1); } DFS(1); Rep(i, 1, n) pr(ans[i]); return 0; }
树状数组:借助差分的思想,答案 = 搜索完u的子树时比节点u权值大的节点 - 未搜索u的子树时比节点u权值大的节点。
const int N = 100005; int n, cnt; int a[N], bit[N], ans[N]; vector<int> id, G[N]; int getId(int x) { return lower_bound(Range(id), x) - id.begin(); } int lowbit(int x) { return x & -x; } void add(int pos) { for (int i = pos; i <= n; i += lowbit(i)) bit[i]++; } int sum(int pos) { int res = 0; for (int i = pos; i; i -= lowbit(i)) res += bit[i]; return res; } void DFS(int u) { cnt++; add(getId(a[u]) + 1); int tp = cnt - sum(getId(a[u]) + 1); for (auto v : G[u]) DFS(v); ans[u] = cnt - sum(getId(a[u]) + 1) - tp; } int main() { sc(n); Rep(i, 1, n) sc(a[i]), id.pb(a[i]); sort(Range(id)); rep(i, 1, n) { int x; sc(x); G[x].pb(i + 1); } cnt = 0; DFS(1); Rep(i, 1, n) pr(ans[i]); return 0; }