NC24048 [USACO 2017 Jan P]Promotion Counting

发布时间 2023-06-23 17:18:36作者: 空白菌

题目链接

题目

题目描述

The cows have once again tried to form a startup company, failing to remember from past experience that cows make terrible managers!

The cows, conveniently numbered 1…N (\(1\leq N\leq 100,000\)), organize the company as a tree, with cow 1 as the president (the root of the tree). Each cow except the president has a single manager (its "parent" in the tree). Each cow i has a distinct proficiency rating, p(i), which describes how good she is at her job. If cow i is an ancestor (e.g., a manager of a manager of a manager) of cow j, then we say j is a subordinate of i.

Unfortunately, the cows find that it is often the case that a manager has less proficiency than several of her subordinates, in which case the manager should consider promoting some of her subordinates. Your task is to help the cows figure out when this is happening. For each cow i in the company, please count the number of subordinates j where p(j)>p(i).

输入描述

The first line of input contains N.
The next N lines of input contain the proficiency ratings p(1)…p(N) for the cows. Each is a distinct integer in the range 1…1,000,000,000.
The next N−1 lines describe the manager (parent) for cows 2…N. Recall that cow 1 has no manager, being the president.

输出描述

Please print N lines of output. The ith line of output should tell the number of subordinates of cow i with higher proficiency than cow i.

示例1

输入

5
804289384
846930887
681692778
714636916
957747794
1
1
2
3

输出

2
0
1
0
0

题解

知识点:DFS序,树状数组。

普通逆序对的公式是:

\[\sum_{i=1}^n \sum_{j<i} [a_j > a_i] \]

即从左到右枚举用时间轴维护先后关系,用树状数组维护数字大小关系。

类似地,我们求出树的dfn序,得到以 \(u\) 为根节点的子树的开始和结束序号 \(L_u,R_u\) ,则树上逆序对公式是:

\[\sum_{i=1}^n \sum_{L_i\leq j \leq R_i} [a_j > a_i] \]

其中 \(L_i \leq j \leq R_i\) 需要时间轴的版本,单纯枚举是处理不了的。我们可以考虑用时间轴维护大小关系,先将 \(a\) 从大到小排序,那么公式转换为:

\[\sum_{i = 1}^n \sum_{a_j > a_i} [L_i \leq j \leq R_i] \]

其中 \(\displaystyle \sum_{a_j > a_i} [L_i \leq j \leq R_i]\) ,在时间轴维护大小关系下,用树状数组即可求出区间出现过的数字个数。

时间复杂度 \(O(n \log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

template<class T>
class Fenwick {
    int n;
    vector<T> node;

public:
    Fenwick(int _n = 0) { init(_n); }

    void init(int _n) {
        n = _n;
        node.assign(n + 1, T());
    }

    void update(int x, T val) { for (int i = x;i <= n;i += i & -i) node[i] += val; }

    T query(int x) {
        T ans = T();
        for (int i = x;i >= 1;i -= i & -i) ans += node[i];
        return ans;
    }
    T query(int l, int r) {
        T ans = T();
        ans += query(r);
        ans -= query(l - 1);
        return ans;
    }
};

struct T {
    int sum;
    T &operator+=(const T &x) { return sum += x.sum, *this; }
    T &operator-=(const T &x) { return sum -= x.sum, *this; }
};

const int N = 100007;
pair<int, int> a[N];
vector<int> g[N];

int dfncnt;
int L[N], R[N];
void dfs(int u) {
    L[u] = ++dfncnt;
    for (auto v : g[u]) dfs(v);
    R[u] = dfncnt;
}

int ans[N];

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++) cin >> a[i].first, a[i].second = i;
    sort(a + 1, a + n + 1, greater<pair<int, int>>());
    for (int i = 2;i <= n;i++) {
        int u;
        cin >> u;
        g[u].push_back(i);
    }
    dfs(1);

    Fenwick<T> fw(n);
    for (int i = 1;i <= n;i++) {
        int u = a[i].second;
        ans[u] = fw.query(L[u], R[u]).sum;
        fw.update(L[u], { 1 });
    }

    for (int i = 1;i <= n;i++) cout << ans[i] << '\n';
    return 0;
}