为啥beginend要拉我做这题呢(
因为他在cf找题的时候突然发现
秋膘-67??????x(当众处刑
然后我们就来大力刷了一下这题
这题就是给你一棵树,对于每个点,每次删掉这个点,删除之后树变成了一个森林,然后我们可以做一次把这个森林里面的某棵树的某个子树与父亲分开,然后把这个子树接到森林里其他树上的操作,问操作完之后的(可以不操作)森林里面树大小的最大值最小是多少
大概想想就是切开这个点,然后把最大的子树中的某个子树接到最小的子树上。
那么显然就是取最接近(max−min)2\frac{(max-min)}{2}2(max−min)大小的子树就是最好的了
然后问题变成了寻找一个子树里面所有可能的子树大小中,最接近这个值的是多少
那如果最大的子树是当前点的子树一切好说,直接在dfs序的一段中用主席树查找就好了
但是如果是父亲那边的子树怎么办呢
那就比较迷幻了
然后beginend大爷又会了,然后告诉我,你可以用一个全局的主席树,减去父亲到根这条链的(因为这条链上实际子树大小要减去当前点的子树大小),然后再减去当前点的子树,在这里面查一次,然后在父亲到根这条链上再单独查一次就好了。
注意要维护次大值,因为次大值的子树大小可能成为新的答案。
/* ***********************************************
Author :BPM136
Created Time :2019/8/12 20:16:06
File Name :G.cpp
************************************************ */
#include <bits/stdc++.h>
#include <sys/timeb.h>
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
#define filein(x) freopen(#x".in","r",stdin)
#define fileout(x) freopen(#x".out","w",stdout)
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define mkd(x) freopen(#x".in","w",stdout);
using namespace std;
int random(int l, int r) {
static std::random_device rd;
struct timeb timeSeed;
ftime(&timeSeed);
size_t seed = timeSeed.time * 1000 + timeSeed.millitm; // milli time
static std::mt19937 gen(seed);
std::uniform_int_distribution<> u(l, r);
return u(gen);
}
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int const N = 100005;
struct segnode {
int lc, rc, s;
} t[N * 120];
int segcnt = 0;
int faroot[N], root[N];
int ver[N], cnt = 0;
int be[N], en[N], sz[N], fa[N];
pii mx[N], mi[N], se[N];
int n;
vector<int> G[N];
inline void addedge(int x, int y) {
G[x].push_back(y);
}
void add(int& k, int lk, int l, int r, int pos, int val) {
k = ++segcnt;
t[k] = t[lk];
t[k].s += val;
if (l == r)
return;
int mid = (l + r) >> 1;
if (pos <= mid)
add(t[k].lc, t[lk].lc, l, mid, pos, val);
else
add(t[k].rc, t[lk].rc, mid + 1, r, pos, val);
}
int queryrig(int k1, int k2, int k3, int k4, int l, int r, int ql, int qr) { //op : 1 right, 0 left
// cerr << t[k1].s << ' ' << t[k2].s << ' ' << t[k3].s << ' ' << t[k4].s << ' ' << l << ' ' << r << '\n';
if (ql <= l && r <= qr) {
if (l == r) {
int num = t[k1].s - t[k2].s + t[k3].s - t[k4].s;
assert(num >= 0);
if (num == 0)
return -1;
return l;
}
int mid = (l + r) >> 1;
int num = t[t[k1].rc].s - t[t[k2].rc].s + t[t[k3].rc].s - t[t[k4].rc].s;
assert(num >= 0);
if (num)
return queryrig(t[k1].rc, t[k2].rc, t[k3].rc, t[k4].rc, mid + 1, r, ql, qr);
else
return queryrig(t[k1].lc, t[k2].lc, t[k3].lc, t[k4].lc, l, mid, ql, qr);
}
int mid = (l + r) >> 1, ret = -1;
if (ql <= mid)
ret = max(ret, queryrig(t[k1].lc, t[k2].lc, t[k3].lc, t[k4].lc, l, mid, ql, qr));
if (qr > mid)
ret = max(ret, queryrig(t[k1].rc, t[k2].rc, t[k3].rc, t[k4].rc, mid + 1, r, ql, qr));
return ret;
}
int querylef(int k1, int k2, int k3, int k4, int l, int r, int ql, int qr) { //op : 1 right, 0 left
if (ql <= l && r <= qr) {
if (l == r) {
int num = t[k1].s - t[k2].s + t[k3].s - t[k4].s;
if (num == 0)
return n + 1;
return l;
}
int mid = (l + r) >> 1;
int num = t[t[k1].lc].s - t[t[k2].lc].s + t[t[k3].lc].s - t[t[k4].lc].s;
if (num == 0)
return querylef(t[k1].rc, t[k2].rc, t[k3].rc, t[k4].rc, mid + 1, r, ql, qr);
else
return querylef(t[k1].lc, t[k2].lc, t[k3].lc, t[k4].lc, l, mid, ql, qr);
}
int mid = (l + r) >> 1, ret = n + 1;
if (ql <= mid)
ret = min(ret, querylef(t[k1].lc, t[k2].lc, t[k3].lc, t[k4].lc, l, mid, ql, qr));
if (qr > mid)
ret = min(ret, querylef(t[k1].rc, t[k2].rc, t[k3].rc, t[k4].rc, mid + 1, r, ql, qr));
return ret;
}
void prework(int x) {
ver[++cnt] = x;
be[x] = cnt;
sz[x] = 1;
auto tr = vector<pii>();
for (auto y : G[x]) {
if (y == fa[x])
continue;
fa[y] = x;
prework(y);
sz[x] += sz[y];
tr.emplace_back(sz[y], y);
}
en[x] = cnt;
if (n - sz[x])
tr.emplace_back(n - sz[x], -1);
sort(all(tr));
mi[x] = tr[0];
mx[x] = tr[SZ(tr) - 1];
se[x] = SZ(tr) >= 2 ? tr[SZ(tr) - 2] : make_pair(-1, -1);
}
void dfs(int x) {
add(faroot[x], faroot[fa[x]], 1, n, sz[x], 1);
for (auto y : G[x]) {
if (y == fa[x])
continue;
dfs(y);
}
}
int main() {
USE_CIN_COUT;
int rt = 0;
cin >> n;
if (n == 1) {
cout << 0 << '\n';
return 0;
}
for (int i = 1; i <= n; ++i) {
int x, y;
cin >> x >> y;
if (x == 0)
rt = y;
else {
addedge(x, y);
addedge(y, x);
}
}
prework(rt);
dfs(rt);
for (int i = 1; i <= n; ++i)
add(root[ver[i]], root[ver[i - 1]], 1, n, sz[ver[i]], 1);
for (int i = 1; i <= n; ++i) {
if (sz[i] == 1) {
cout << n - 1 << '\n';
continue;
}
int pos = (mx[i].first - mi[i].first) / 2;
if (pos == 0) {
cout << mx[i].first << '\n';
continue;
}
if (mx[i].second == -1) {
int x = i;
int t1 = queryrig(root[ver[n]], root[ver[en[x]]], root[ver[be[x]]], faroot[x], 1, n, 1, pos);
int t2 = querylef(root[ver[n]], root[ver[en[x]]], root[ver[be[x]]], faroot[x], 1, n, pos + 1, n);
int ans = min(max(mx[i].first - t1, mi[i].first + t1), max(mx[i].first - t2, mi[i].first + t2));
if (pos + sz[x] <= n) {
t1 = queryrig(faroot[fa[x]], 0, 0, 0, 1, n, 1, pos + sz[x]) - sz[x];
if (t1 >= 0)
ans = min(ans, max(mx[i].first - t1, mi[i].first + t1));
if (pos + sz[x] < n) {
t2 = querylef(faroot[fa[x]], 0, 0, 0, 1, n, pos + sz[x] + 1, n) - sz[x];
if (t2 >= 0)
ans = min(ans, max(mx[i].first - t2, mi[i].first + t2));
}
}
if (se[i].first != -1)
ans = max(ans, se[i].first);
cout << ans << '\n';
} else {
int x = mx[i].second;
int t1 = queryrig(root[ver[en[x]]], root[ver[be[x]]], 0, 0, 1, n, 1, pos); ////1 means right
int t2 = querylef(root[ver[en[x]]], root[ver[be[x]]], 0, 0, 1, n, pos + 1, n); ////0 means left
int ans = min(max(mx[i].first - t1, mi[i].first + t1), max(mx[i].first - t2, mi[i].first + t2));
if (se[i].first != -1)
ans = max(ans, se[i].first);
cout << ans << '\n';
}
}
return 0;
}