[USACO17JAN]Promotion Counting 题解

前言

巨佬说:要有线段树,结果蒟蒻打了一棵树状数组...
想想啊,奶牛都开公司当老板了,我还在这里码代码,太失败了。
话说奶牛开个公司老板不应该是FarmerJohn吗

题解

刚看到这道题的时候竟然没有想到深搜,然后仔细一想,发现果然要用深搜
但是这个树形结构怎么维护是一个问题?难道打个欧拉序...
其实做法非常简单,首先按照套路我们把牛的能力值离散化(由于没有相同的值,所以这个离散化非常简单)。
然后重点来了,建立一个维护某一能力值牛的个数的树状数组
我们深搜到一个点的时候,我们不希望计算的部分是比它大的祖先,而希望计算的部分是比它大的儿子。
于是我们在搜到这个点的时候将它的答案减去当前树状数组里能力值比它大的牛的个数(减去祖先部分),然后我们搜索它的所有儿子。
搜索完成后,我们将它的答案加上当前树状数组里比它大的牛的个数(加上儿子和祖先部分)。所以一加一减只剩下儿子的部分。
然后输出我们的答案数组,就AC了。

代码

#include <cstdio>
#include <algorithm>
#define ll long long

using namespace std;

ll read(){
	ll x = 0; int zf = 1; char ch = ' ';
	while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
	if (ch == '-') zf = -1, ch = getchar();
	while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

struct Edge{
	int to, next;
} edges[200005];

int head[100005], edge_num = 0;

void addEdge(int from, int to){
	edges[++edge_num] = (Edge){to, head[from]};
	head[from] = edge_num;
}

int n;

namespace FenTree{
	#define lowbit(x) (x&-x)
	int BIT[100005];
	int query(int i){
		int res = 0;
		for ( ; i; i -= lowbit(i)) res += BIT[i]; return res;
	}
	void add(int i){
		for ( ; i <= n; i += lowbit(i)) ++BIT[i];
	}
	#undef lowbit
};

using namespace FenTree;

int p[100005], dy[100005];
int ans[100005];

bool Comp(const int &a, const int &b){return p[a] > p[b];};

void DFS(int u, int fa){
	ans[u] -= query(p[u]);
	for (int c_e = head[u]; c_e; c_e = edges[c_e].next)
		if (edges[c_e].to != fa) DFS(edges[c_e].to, u);
	ans[u] += query(p[u]); add(p[u]);
}

int main(){
	n = read();
	for (int i = 1; i <= n; ++i) p[i] = read(), dy[i] = i;
	sort(dy + 1, dy + n + 1, Comp);
	for (int i = 1; i <= n; ++i) p[dy[i]] = i;
	for (int i = 2; i <= n; ++i){int x = read(); addEdge(i, x), addEdge(x, i);}
	DFS(1, 1);
	for (int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
	return 0;
}
posted @ 2019-07-03 21:40  LinZhengmin  阅读(190)  评论(0编辑  收藏  举报

Contact with me