题目大意
大小为 (n) 以 (1) 为根的树,点带权,求每个子树内大于本点的点的数量
(1 le n le 10^5,1 le p_i le 10^9)
题解
一眼静态链分治,然后统计?
离散化后树状数组维护即可
时间复杂度 (n log ^2 (n))
(Code)
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
int n, h[N], tot;
struct edge{int to, nxt;}e[N];
inline void add(int x, int y){e[++tot] = edge{y, h[x]}, h[x] = tot;}
struct node{int p, id;}a[N];
inline bool cmp1(node x, node y){return x.p < y.p;}
inline bool cmp2(node x, node y){return x.id < y.id;}
int dfc, fa[N], siz[N], dfn[N], rev[N], son[N], ans[N];
void dfs1(int x)
{
siz[x] = 1, dfn[x] = ++dfc, rev[dfc] = x;
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
dfs1(v), siz[x] += siz[v];
if (siz[v] > siz[son[x]]) son[x] = v;
}
}
int c[N];
inline int lowbit(int x){return x & (-x);}
inline void update(int x, int v){for(; x <= n; x += lowbit(x)) c[x] += v;}
inline int query(int x)
{
int res = 0;
for(; x; x -= lowbit(x)) res += c[x];
return res;
}
void dfs2(int x, int kp)
{
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == son[x]) continue;
dfs2(v, 0);
}
if (son[x]) dfs2(son[x], 1);
for(register int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == son[x]) {update(a[son[x]].p, 1); continue;}
for(register int j = dfn[v]; j <= dfn[v] + siz[v] - 1; j++) update(a[rev[j]].p, 1);
}
ans[x] = siz[x] - 1 - query(a[x].p);
if (!kp) for(register int i = dfn[x] + 1; i <= dfn[x] + siz[x] - 1; i++) update(a[rev[i]].p, -1);
}
int main()
{
scanf("%d", &n);
for(register int i = 1; i <= n; i++) scanf("%d", &a[i].p), a[i].id = i;
sort(a + 1, a + n + 1, cmp1);
for(register int i = 1; i <= n; i++) a[i].p = i;
sort(a + 1, a + n + 1, cmp2);
for(register int i = 2; i <= n; i++) scanf("%d", &fa[i]), add(fa[i], i);
dfs1(1), dfs2(1, 1);
for(register int i = 1; i <= n; i++) printf("%d
", ans[i]);
}