[USACO17JAN]Promotion Counting P

题目大意

大小为 (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]);
}
原文地址:https://www.cnblogs.com/leiyuanze/p/14327605.html