题目链接:https://www.luogu.com.cn/problem/P3605
解题思路:
首先需要离散化一下。
然后就是套 树上启发式合并模板了,期间用树状数组维护一下区间和。
时间复杂度:\(O(n \log^2 n)\)。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, a[maxn], sz[maxn], ans[maxn];
bool big[maxn];
vector<int> g[maxn];
int bit[maxn];
int lowbit(int x) {
return x & -x;
}
void add(int p, int val) {
while (p <= n) {
bit[p] += val;
p += lowbit(p);
}
}
int query(int p) {
int res = 0;
while (p) {
res += bit[p];
p -= lowbit(p);
}
return res;
}
void dfs_add(int u, int c) {
add(a[u], c);
for (auto v : g[u])
if (!big[v])
dfs_add(v, c);
}
void dfs0(int u) {
sz[u] = 1;
for (auto v : g[u])
dfs0(v), sz[u] += sz[v];
}
void dfs(int u, bool keep) {
int son = 0;
for (auto v : g[u])
if (sz[v] > sz[son])
son = v;
for (auto v : g[u])
if (v != son)
dfs(v, false);
if (son)
dfs(son, true),
big[son] = true;
dfs_add(u, 1);
ans[u] = query(n) - query(a[u]);
if (son)
big[son] = false;
if (!keep)
dfs_add(u, -1);
}
void lsh() {
vector<int> v;
for (int i = 1; i <= n; i++) v.push_back(a[i]);
sort(v.begin(), v.end());
for (int i = 1; i <= n; i++)
a[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", a+i);
lsh();
for (int i = 2; i <= n; i++) {
int p;
scanf("%d", &p);
g[p].push_back(i);
}
dfs0(1);
dfs(1, 1);
for (int i = 1; i <= n; i++)
printf("%d\n", ans[i]);
return 0;
}