线段树合并裸题。线段树的下标维护的是能力指数,需要离散化。统计答案可以在线段树上查询后缀和。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1e5 + 100;
struct Edge {
int v, nxt;
} e[N << 1];
struct Node {
int lc, rc;
int v;
} tr[N * 21];
vector<int> vec;
int a[N], n, m, cnt, idx, ans[N], head[N], root[N];
int get(int x) {
return lower_bound(vec.begin(), vec.end(), x) - vec.begin();
}
void Add(int u, int v) {
e[++cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
void pushup(int u) {
tr[u].v = tr[tr[u].lc].v + tr[tr[u].rc].v;
}
void insert(int u, int l, int r, int k, int v) {
if( l == r) {
tr[u].v += v;
return;
}
int mid = l + r >> 1;
if(k <= mid) {
if( !tr[u].lc) tr[u].lc = ++ idx;
insert(tr[u].lc, l, mid, k, v);
}
else {
if( !tr[u].rc) tr[u].rc = ++ idx;
insert(tr[u].rc, mid + 1, r, k, v);
}
pushup(u);
}
int query(int u, int l, int r, int k) {//查询后缀和
if( l >= k) {
return tr[u].v;
}
int mid = l + r >> 1;
int res = 0;
if( k <= mid) {
if(tr[u].lc)
res += query(tr[u].lc, l, mid, k);
}
if( tr[u].rc)
res += query(tr[u].rc, mid + 1, r, k);
return res;
}
int merge(int p, int q, int l, int r) {
if( !p || !q)
return p + q;
if( l == r) {
tr[p].v += tr[q].v;
return p;
}
int mid = l + r >> 1;
tr[p].lc = merge(tr[p].lc, tr[q].lc, l, mid);
tr[p].rc = merge(tr[p].rc, tr[q].rc, mid + 1, r);
pushup(p);
return p;
}
void dfs(int u) {
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
dfs(v);
root[u] = merge(root[u], root[v], 1, (int)vec.size());
}
ans[u] = query(root[u], 1, (int)vec.size(), a[u]) - 1;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
root[i] = i;
idx = n;
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
vec.push_back(a[i]);
}
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
for(int i = 1; i <= n; i ++) {
a[i] = get(a[i]) + 1;
insert(root[i], 1, (int)vec.size(), a[i], 1);
}
for(int i = 2; i <= n; i ++) {
int x;
scanf("%d", &x);
Add(x, i);
}
dfs(1);
for(int i = 1; i <= n; i ++)
printf("%d
", ans[i]);
return 0;
}