Promotion Counting

Promotion Counting

官方解答(英文)

  1. 因为子树在遍历数组上是连续的区间,所以问题就转化为在区间上求大于一个值的元素个数的问题。
  2. 怎么求的关键点,是用离线法(Milk Visits也用了这个方法),把元素从大到小往线段树中添加值为1的flags,然后就直接区间求和就行了。
  3. 元素值是唯一的,所以比较友好。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
 
int n;
pi p[100005];
vector<int> adj[100005];
int st[100005], en[100005];     // range of subtree in traversal array
int ans[100005];
int tree[200005];               // segment tree over traversal array for 
                                // flags of values less than current
 
void set(int k, int x) {
    k += n;
    tree[k] = x;
    for (k /= 2; k >= 1; k /= 2) {
        tree[k] = tree[2*k]+tree[2*k+1];
    }
}
 
int sum(int a, int b) {
    a += n; b += n;
    int s = 0;
    while (a <= b) {
        if (a%2 == 1) s += tree[a++];
        if (b%2 == 0) s += tree[b--];
        a /= 2; b /= 2;
    }
    return s;
}
 
int ti;
void dfs(int s) {
    st[s] = ti++;
    for (int u: adj[s])
        dfs(u);
    en[s] = ti-1;
}
 
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &p[i].first);
        p[i].second = i;
    }
    for (int i = 1; i < n; i++) {
        int fa;
        scanf("%d", &fa);
        adj[fa-1].push_back(i);        
    }
    dfs(0);     // find st and en for each subtree
    sort(p, p+n, greater<pi>());   // decreasing
    for (int i = 0; i < n; i++) {   // adding nodes by decreasing p values and count
        int id = p[i].second, pv = p[i].first;
        ans[id] = sum(st[id], en[id]);
        set(st[id], 1);
    }
    for (int i = 0; i < n; i++)
        printf("%d\n", ans[i]);
    return 0;
}
 
 
/*
Example:
 
      1 (80)
     / \
(84)2   3(68)
    |   |
(71)4   5(95)
 
*/