[USACO17JAN] Promotion Counting P 题解

[USACO17JAN] Promotion Counting P 题解

前言

好久没写题解了,今天趁我心情好赶紧水一篇。

思路

首先拿到这题,关键词检索:子树,比 \(p_i\) 大的,树状数组!现在考虑如何去掉其他子树的贡献……emm,我直接在算贡献的时候去掉其他子树的贡献不就好了!

当然,暴力去贡献复杂度肯定爆炸,这里考虑如何通过保留最多的信息来达到减少复杂度的目的。这里用了 DSU on Tree 的思想:保留重儿子的信息,而在递归完轻儿子后清空轻儿子的信息。每个点被再次遍历到,当且仅当它所在的子树大小翻倍。这样做复杂度是 \(O(n \log n)\) 的,套上树状数组的复杂度就是 \(O(n \log^2 n)\) 的。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100;

int read() {
	int x = 0; char ch = getchar();
	while(ch<'0' || ch>'9') ch = getchar();
	while(ch>='0'&&ch<='9') x = x*10+(ch-48), ch = getchar();
	return x;
}
int n;
int lsh[N], a[N];
//dsu on tree?
int head[N], tot;
struct node {
	int nxt, to;
} edge[N<<1];
void add(int u, int v) {
	edge[++tot].nxt = head[u];
	edge[tot].to = v;
	head[u] = tot;
}

struct BIT {
	int tc[N];
	int lowbit(int x) {
		return x & (-x);
	}
	void insert(int pos, int val) {
//		printf("%d %d\n", pos, val);
		for(int i = pos; i<=n; i+=lowbit(i)) {
			tc[i]+=val;
		}
	}
	int query(int pos) {
		int ret = 0;
		for(int i = pos; i; i-=lowbit(i)) {
			ret+=tc[i];
		}
		return ret;
	}
}bt;
int siz[N], son[N];
void predfs(int u, int fath) {
	siz[u] = 1;
	for(int i = head[u]; i; i = edge[i].nxt) {
		int v = edge[i].to;
		if(v == fath) continue;
		predfs(v, u);
		siz[u]+=siz[v];
		if(siz[son[u]] < siz[v]) son[u] = v;
	}
}

int ans[N];
void pls(int u, int fath) {
	bt.insert(a[u], 1);
	for(int i = head[u]; i; i = edge[i].nxt) {
		int v = edge[i].to;
		if(v == fath) continue;
		pls(v, u);
	}
}
void del(int u, int fath) {
	bt.insert(a[u], -1);
	for(int i = head[u]; i; i = edge[i].nxt) {
		int v = edge[i].to;
		if(v == fath) continue;
		del(v, u);
	}
}
void dfs(int u, int fath, bool op) {
	for(int i = head[u], v; i; i = edge[i].nxt) {
		v = edge[i].to;
		if(v == fath || v == son[u]) continue;
		dfs(v, u, 1);
	}
	
	if(son[u]) dfs(son[u], u, 0);
	
	for(int i = head[u], v; i; i = edge[i].nxt) {
		v = edge[i].to;
		if(v == fath || v == son[u]) continue;
		pls(v, u); 
	}
	ans[u] = bt.query(n) - bt.query(a[u]);
	bt.insert(a[u], 1);
//	cout << u << " " << bt.query(n) << " " << bt.query(a[u]) << endl;
	if(op) del(u, fath);
}
int main() {
	n = read();
	for(int i = 1; i<=n; ++i) {
		a[i] = lsh[i] = read();
	}
	sort(lsh+1, lsh+n+1);
	for(int i = 1; i<=n; ++i) {
		a[i] = lower_bound(lsh+1, lsh+n+1, a[i])-lsh;
	}
	for(int i = 2; i<=n; ++i) {
		int u = read();
		add(u, i);
		add(i, u);
	}
	predfs(1, 0);
	dfs(1, 0, 0);
	for(int i = 1; i<=n; ++i) {
		printf("%d\n", ans[i]);
	}
	return 0;
}

后记:

后来翻题解发现自己完全是搞麻烦了。其实这个题在递归前后做个差就好……麻了。

完全不会捏 🤡👈😂

posted @ 2023-10-11 21:56  霜木_Atomic  阅读(18)  评论(0编辑  收藏  举报