题目
奶牛们又一次试图创建一家创业公司,还是没有从过去的经验中吸取教训–牛是可怕的管理者!
为了方便,把奶牛从 1 ⋯ N ( 1 ≤ N ≤ 100 , 000 ) 1\cdots N(1 \leq N \leq 100, 000) 1⋯N(1≤N≤100,000)编号,把公司组织成一棵树, 1 1 1 号奶牛作为总裁(这棵树的根节点)。除了总裁以外的每头奶牛都有一个单独的上司(它在树上的 “双亲结点”)。所有的第 i i i头牛都有一个不同的能力指数 p(i),描述了她对其工作的擅长程度。如果奶牛 i i i 是奶牛 j j j的祖先节点(例如,上司的上司的上司),那么我们我们把奶牛 j j j叫做 i i i的下属。
不幸地是,奶牛们发现经常发生一个上司比她的一些下属能力低的情况,在这种情况下,上司应当考虑晋升她的一些下属。你的任务是帮助奶牛弄清楚这是什么时候发生的。简而言之,对于公司的中的每一头奶 i i i,请计算其下属 j j j的数量满足 p ( j ) > p ( i ) p(j) > p(i) p(j)>p(i)。
题解
- 首先,每个 p i p_i pi都非常的大,那么我们就考虑离散化。
- 而对于我们要求解的答案的形式,其实就是一个类逆序对的形式
- 因此我们可以仿照线性逆序对的形式,在 p i p_i pi的值域范围内维护一个树状数组
- 在处理时应注意右子树的答案不能影响到左子树,我们在只需在统计左子树时减去右子树的答案即可
- 在离散化时从大到小排即最大的数映射为 1 1 1(题目要求)
code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 100;
int n, m, tot;
int p[maxn], _p[maxn], lin[maxn], c[maxn];
int ans[maxn];
struct node {
int next, to;
} e[maxn << 1];
inline bool cmp(int x, int y) { return p[x] > p[y]; }
inline void add(int from, int to) {
e[++tot].to = to;
e[tot].next = lin[from];
lin[from] = tot;
}
inline void change(int x, int val) {
for (; x <= n; x += x & (-x)) c[x] += val;
}
inline int query(int x) {
int ret = 0;
for (; x; x -= x & (-x)) ret += c[x];
return ret;
}
void dfs(int u) {
ans[u] = -query(p[u]);
for (int i = lin[u]; i; i = e[i].next) {
int v = e[i].to; dfs(v);
}
ans[u] += query(p[u]);
change(p[u], 1);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &p[i]), _p[i]= i;
sort(_p + 1, _p + n + 1, cmp);
for (int i = 1; i <= n; ++i) p[_p[i]] = i;
for (int i = 1; i <= n; ++i) printf("%d ", p[i]);
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\n", ans[i]);
return 0;
}