首页 > 其他分享 >Two Centroids

Two Centroids

时间:2023-08-24 20:11:17浏览次数:32  
标签:rt ch int Two Centroids read 子树 mx

Two Centroids

先考虑对于一棵树,至少要加多少个点才能有两个重心。
以重心为根,设最大儿子的子树大小为 \(mx\),那么答案就为 \((n - mx) - mx = n - 2mx\)。
接下来考虑如何在加点时维护最大子树,一个显然的性质,加一个点重心最多偏移一位,如果重心偏移,那么 \(mx = \lfloor \frac{n}{2} \rfloor\)。所以我们可以每次加一个点,用倍增寻找其的子树的根,在动态的查询子树大小来更新 \(mx\),用树状数组根据出现时间计数即可,时间复杂度为 \(O(n \log n)\)。

Code
#include<bits/stdc++.h>
#define LL long long
#define eb emplace_back
#define IN inline
using namespace std;
const int N = 5e5 + 5;
int n;

IN int read() {
	int t = 0,res = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) t |= (ch == '-');
	for (; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ 48);
	return t ? -res : res;
}
int g[N], dfn[N], dfc, dep[N], f[N][22], siz[N];
vector<int> E[N];
int lowbit(int x){return x & -x;}
void add(int x, int v) {
	for (; x <= n; x += lowbit(x)) g[x] += v; 
}
int query(int x) {
	int res = 0;
	for (; x; x -= lowbit(x)) res += g[x];
	return res;
}
void dfs(int u, int fa) {
	dfn[u] = ++dfc, dep[u] = dep[fa] + 1, f[u][0] = fa, siz[u] = 1;
	for (int i = 1; i <= 20; i++)
		if (f[u][i - 1]) f[u][i] = f[f[u][i - 1]][i - 1];
		else break;
	for (auto v : E[u]) dfs(v, u), siz[u] += siz[v];
}
int find(int rt, int x) {
	int tmp = dep[x] - dep[rt] - 1;
	if (tmp < 0) return -1;
	for (int i = 0; tmp; tmp >>= 1, i++)
		if (tmp & 1) x = f[x][i];
	if (f[x][0] == rt) return x;
	return -1;
}
int main() {
	for (int T = read(); T; T--) {
		n = read(), dfc = 0;
		for (int i = 1; i <= n; i++) {
			E[i].clear();
			for (int j = 0; j <= 20; j++) f[i][j] = 0;
		}
		for (int i = 2, q; i <= n; i++) q = read(), E[q].eb(i);
		dfs(1, 1); int rt = 1, mx = 0;
		add(dfn[1], 1);
		for (int i = 2; i <= n; i++) {
			add(dfn[i], 1);
			int x = find(rt, i);
			if (x != -1) {
				int s = query(dfn[x] + siz[x] - 1) - query(dfn[x] - 1);
				mx = max(mx, s);
				if (mx > i / 2) mx = i / 2, rt = x;
			}else {
				int s = query(dfn[rt] + siz[rt] - 1) - query(dfn[rt] - 1);
				mx = max(mx, i - s);
				if (mx > i / 2) mx = i / 2, rt = f[rt][0];
			}
			printf("%d ", i - mx * 2); 
		}
		puts("");
		for (int i = 1; i <= n; i++) add(dfn[i], -1);
	}
}

标签:rt,ch,int,Two,Centroids,read,子树,mx
From: https://www.cnblogs.com/nibabadeboke/p/17655055.html

相关文章