首页 > 其他分享 >CodeForces 1827 D Two Centroids

CodeForces 1827 D Two Centroids

时间:2023-05-16 18:56:01浏览次数:49  
标签:typedef int 1827 CodeForces Centroids len maxn long mx

洛谷传送门

CF 传送门

考虑固定一个重心,设 \(k\) 为重心最大子树大小,答案为 \(n - 2k\)。构造方法是往最大的子树塞叶子。

树的重心有一个很好的性质,就是加一个叶子,重心最多移动一条边的距离。简单证一下,设重心为 \(x\),往儿子 \(u\) 的子树中加叶子。

  • 如果 \(sz_u > \left\lfloor\frac{n}{2}\right\rfloor\),那么 \(sz_u - 1 = \left\lfloor\frac{n}{2}\right\rfloor\),并且 \(x\) 的其他子树大小 \(< \left\lfloor\frac{n}{2}\right\rfloor\),那么 \(x\) 会下移到 \(u\);
  • 否则无事发生。

考虑树状数组维护每个点子树的大小,当前重心和当前的 \(k\)。只用考虑下移一条边的情况,因此是容易维护的。时间复杂度 \(O(n \log n)\)。

code
// Problem: D. Two Centroids
// Contest: Codeforces - Codeforces Round 873 (Div. 1)
// URL: https://codeforces.com/contest/1827/problem/D
// Memory Limit: 1024 MB
// Time Limit: 1500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 500100;
const int logn = 22;

int n, head[maxn], len, st[maxn], times, ed[maxn], f[maxn][logn], dep[maxn];
struct edge {
	int to, next;
} edges[maxn];

inline void add_edge(int u, int v) {
	edges[++len].to = v;
	edges[len].next = head[u];
	head[u] = len;
}

namespace BIT {
	int c[maxn];
	
	inline void init() {
		for (int i = 1; i <= n; ++i) {
			c[i] = 0;
		}
	}
	
	inline void update(int x, int d) {
		for (int i = x; i <= n; i += (i & (-i))) {
			c[i] += d;
		}
	}
	
	inline int query(int x) {
		int res = 0;
		for (int i = x; i; i -= (i & (-i))) {
			res += c[i];
		}
		return res;
	}
	
	inline int query(int l, int r) {
		return query(r) - query(l - 1);
	}
}

void dfs(int u) {
	st[u] = ++times;
	for (int i = 1; i <= 20; ++i) {
		f[u][i] = f[f[u][i - 1]][i - 1];
	}
	for (int i = head[u]; i; i = edges[i].next) {
		int v = edges[i].to;
		f[v][0] = u;
		dep[v] = dep[u] + 1;
		dfs(v);
	}
	ed[u] = times;
}

inline int jump(int x, int k) {
	for (int i = 0; i <= 20; ++i) {
		if (k & (1 << i)) {
			x = f[x][i];
		}
	}
	return x;
}

void solve() {
	len = 0;
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		head[i] = 0;
	}
	for (int i = 2, p; i <= n; ++i) {
		scanf("%d", &p);
		add_edge(p, i);
	}
	times = 0;
	dfs(1);
	BIT::init();
	BIT::update(st[1], 1);
	int x = 1, mx = 0;
	for (int u = 2; u <= n; ++u) {
		BIT::update(st[u], 1);
		if (st[x] <= st[u] && st[u] <= ed[x]) {
			int v = jump(u, dep[u] - dep[x] - 1);
			int t = BIT::query(st[v], ed[v]);
			if (t > u / 2) {
				x = v;
				mx = u / 2;
			} else {
				mx = max(mx, t);
			}
		} else {
			int t = u - BIT::query(st[x], ed[x]);
			if (t > u / 2) {
				x = f[x][0];
				mx = u / 2;
			} else {
				mx = max(mx, t);
			}
		}
		printf("%d ", u - mx * 2);
	}
	putchar('\n');
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:typedef,int,1827,CodeForces,Centroids,len,maxn,long,mx
From: https://www.cnblogs.com/zltzlt-blog/p/17406513.html

相关文章

  • CodeForces 1827 B Range Sorting
    洛谷传送门CF传送门考虑拆贡献\(i-1\simi\),发现当\([1,i-1]\)的最大值大于\([i,n]\)的最小值时\(i-1\simi\)产生\(1\)的贡献。考虑枚举左端点\(j\),设\(x=\max\limits_{k=j}^{i-1}a_k\)。设\(i\)及\(i\)以后第一个\(<x\)的数位置是\(p\),那么......
  • Codeforces 1158E - Strange device(交互)
    一个有点烦的\(8\logn\)的做法。大致想法大家都一样:以\(1\)为根,然后先问出每个点深度,再问出每个点的父亲。首先先用一个log的做法问出树高,具体做法是直接令根节点的\(f\)为二分出的\(mid\),看能否覆盖所有点即可,记最大深度为\(mxdep\)。可以在二分过程中顺带着求出深......
  • Codeforces 1423C - Dušan's Railway(树分块)
    首先\(k>3\)当\(k=3\)做,也就是说题目等价于找不超过\(10n\)条路径使得任意两点间的路径都可以表示为选定的这些路径中不相交的三者的并。先考虑链怎么做,关于这个\(3\),很自然的想法是取若干关键点,关键点之间两两连边,其余点再像相邻两关键点连边,因此考虑分块,每\(B\)个点设......
  • Codeforces Round 873 (Div. 2)
    CodeforcesRound873(Div.2)A-DivisibleArray思路:每个数为i时都为i的倍数,前n个数和为Sn=n*(n+1)/2,可知每个数再乘n,Sn必为n的倍数#include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>PII;typedefpair<string,int>PSI;constintN=3e5+5,INF=0x3f3f3f3......
  • Codeforces Round 873 (Div. 2)(A,B,C)
    A//由求和公式(n*(n-1))/2知道当n为偶数就行,我们将每个序号乘以2就满足了#include<iostream>usingnamespacestd;constintN=210;intt;intn;intmain(){cin>>t;while(t--){cin>>n;for(inti=1;i<......
  • Codeforces Round #358 (Div. 2) -- B. Alyona and Mex (思路水题)
    B.AlyonaandMextimelimitpertestmemorylimitpertestinputoutputSomeonegaveAlyonaanarraycontainingnpositiveintegersa1, a2, ..., an.Inoneoperation,Alyonacanchooseanyelementofthearray......
  • Codeforces Round 869
    \(\texttt{A.AlmostIncreasingSubsequence}\)把\(a_i>a_{i+1}\)的极长下降区间称为一个段,那么显然,一个长度为\(len\)的极长下降区间最多选\(\min(2,len)\)个,并且可以达到这个数,因此记录每个位置属于哪个段,记录个前缀和就好了。#include<bits/stdc++.h>usingnamespaces......
  • Educational Codeforces Round 148 [Rated for Div. 2]A~C
    A#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;constintN=60;charc[N];voidrun(){ scanf("%s",c+1); intn=strlen(c+1); map<char,int>st; st[c[1]]++; for(inti=2;i<=n/2;++i) ......
  • Educational Codeforces Round 148 (Rated for Div. 2) A-D 题解
    比赛地址A.NewPalindrome题意:给一个回文串,判断是否能重新排成另一个回文串Solution存不同对的个数即可voidsolve(){ strings; cin>>s; intn=s.length(); set<char>st; for(inti=0;i<n/2;i++) { st.insert(s[i]); } if(st.size()>1)cout<<"YES\n"; els......
  • Codeforces 1781H1 - Window Signals (easy version)
    很套路的一道题,把F1写了,F2感觉和F1gap不太大就懒得写了/shui首先需要明白大致思路:直接计算\(2^{nm-k}-1\)之所以会算重,是因为对于同一种图案,可能把它放在很多位置都是合法的。那么显然我们需要选一个代表元来把它的贡献唯一化,非常自然的想法就是把它固定在最左上角那个合......