题目链接
题意:给你一棵以 1 1 1为根节点的树和每个点的点权,问在每个子树中,有多少个子节点的点权小于根节点。
题解:
首先对值进行离散后,之后有两种方法可以解决。
- 树状数组
求有几个比一个值小的值,想到了树状数组。对树从树根进行 d f s dfs dfs,每次 d f s dfs dfs到一个点的时候,先减去当前树状数组中比这个节点值小的个数,最后 d f s dfs dfs完之后再加回去。答案 = - 祖先 + (祖先 + 子节点),所以得出了答案。
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define dbg(x...) do { cout << #x << " -> "; err(x); } while (0)
void err() { cout << endl; }
template <class T, class... Ts>
void err(const T& arg, const Ts&... args) {
cout << arg << ' '; err(args...);
}
typedef long long ll;
const int maxn = 1e5 + 7;
vector<int> G[maxn];
struct Node{
int v, id;
}node[maxn];
bool cmp(Node a, Node b) {
return a.v < b.v;
}
int n, sum[maxn], ans[maxn], id[maxn];
int lowbit(int x) {return x & (-x);}
void add(int i) {
while (i <= n) {
sum[i] += 1;
i += lowbit(i);
}
}
int query(int i) {
int res = 0;
while (i > 0) {
res += sum[i];
i -= lowbit(i);
}
return res;
}
void dfs(int u) {
ans[u] -= query(n) - query(id[u]);
for (auto v : G[u] ) {
add(id[v]);
dfs(v);
}
ans[u] += query(n) - query(id[u]);
}
void solve() {
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> node[i].v;
node[i]. id = i;
}
sort(node + 1, node + 1 + n, cmp);
for (int i = 1; i<= n; ++i) {
id[node[i].id] = i;
}
for (int i = 2, v; i <= n; ++i) {
cin >> v;
G[v].push_back(i);
}
dfs(1);
for (int i = 1; i <= n; ++i) {
cout << ans[i] << endl;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int _T = 1;
// cin >> _T;
while (_T--) solve();
return 0;
}
- 线段树合并
对每个子节点建立一棵权值线段树,合并完子树后询问比他大的值的个数。
#include <bits/stdc++.h>
using namespace std;
#define lson t[id].l
#define rson t[id].r
typedef long long ll;
template <class T> inline void read(T &x) {
int f = 0; x = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
if (f) x = -x;
}
const int maxn = 1e5 + 7;
struct Seg{
int l, r;
int num;
}t[maxn * 50];
int n, tot, cor[maxn], rt[maxn], a[maxn], c[maxn];
int ans[maxn];
vector<int> G[maxn];
void up(int id) {
t[id].num = t[lson].num + t[rson].num;
}
void modify(int &id, int l, int r, int p) {
if(!id) id = ++tot;
if (l == r) {
t[id].num++;
return;
}
int mid = l + r >> 1;
if (p <= mid) modify(lson, l, mid, p);
else modify(rson, mid + 1, r, p);
up(id);
}
int merge(int a, int b, int l, int r) {
if (!a) return b;
if (!b) return a;
if (l == r) {
t[a].num += t[b].num;
return a;
}
int mid = l + r >> 1;
t[a].l = merge(t[a].l, t[b].l, l, mid);
t[a].r = merge(t[a].r, t[b].r, mid + 1, r);
up(a);
return a;
}
int query(int id, int l, int r, int ql, int qr) {
int res = 0;
if (!id || ql > qr) return 0;
if (ql <= l && qr >= r) return t[id].num;
int mid = l + r >> 1;
if (ql <= mid) res += query(lson, l, mid, ql, qr);
if (qr > mid) res += query(rson, mid + 1, r, ql, qr);
return res;
}
void dfs(int u) {
for (auto v : G[u]) {
dfs(v);
merge(u, v, 1, n);
}
ans[u] = query(u, 1, n, cor[u] + 1, n);
modify(u, 1, n, cor[u]);
}
void solve() {
read(n);
tot = n;
for (int i = 1; i <= n; ++i) read(a[i]), c[i] = a[i];
sort(c + 1, c + 1 + n);
int q = unique(c + 1, c + 1 + n) - c - 1;
for (int i = 1; i <= n; ++i) {
cor[i] = lower_bound(c + 1, c + 1 + q, a[i]) - c;
}
for (int i = 2, u; i <= n; ++i) {
read(u);
G[u].push_back(i);
}
dfs(1);
for (int i = 1; i <= n; ++i) {
printf("%d\n", ans[i]);
}
}
int main() {
int _T = 1;
while (_T--) solve();
return 0;
}