CompetitiveProgramming/src/bin/at-abc337g.cc

145 lines
4.1 KiB
C++
Raw Normal View History

2024-02-27 03:42:51 +00:00
#include <bits/stdc++.h>
using namespace std;
template <class __Tp>
struct fenwick : std::vector<__Tp> {
size_t n;
fenwick(const size_t &_n) : std::vector<__Tp>(_n + 1), n(_n) {}
fenwick() {}
void update(const int &x, const __Tp &val) {
assert(x > 0);
for (int i = x; i <= n; i += i & -i) {
(*this)[i] += val;
}
}
__Tp query(const int &x, __Tp res = 0) {
assert(x >= 0);
for (int i = x; i; i -= i & -i) {
res += (*this)[i];
}
return res;
}
};
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n;
cin >> n;
vector<vector<int>> g(n + 1);
for (int i = 1, u, v; i < n; i++) {
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> F(n + 1), G(n + 1);
fenwick<int> tr(n);
vector<int> dep(n + 1), ls(n + 1, -1), l(n + 1), r(n + 1), id(n + 1), sz(n + 1);
int t = 0;
function<void(int, int)> dfs = [&](int x, int fa) {
l[x] = ++t;
id[t] = x;
dep[x] = dep[fa] + 1;
for (auto y : g[x]) {
if (y == fa) continue;
dfs(y, x);
sz[x] += sz[y];
if (ls[x] == -1 || sz[y] > sz[ls[x]]) ls[x] = y;
}
sz[x]++;
r[x] = t;
};
dfs(1, 0);
function<void(int, int, int)> solveF = [&](int x, int fa, int keep) {
cerr << "Calling solveF, x = " << x << ", fa = " << fa << ", keep = " << keep << endl;
for (auto y : g[x]) {
if (y != fa && y != ls[x]) {
solveF(y, x, 0);
}
}
if (ls[x] != -1) {
solveF(ls[x], x, 1);
}
for (auto y : g[x]) {
if (y == fa || y == ls[x]) continue;
for (int j = l[y]; j <= r[y]; j++) tr.update(id[j], 1);
}
tr.update(x, 1);
F[x] = tr.query(fa);
cerr << "Writing F[x] = " << F[x] << endl;
if (!keep) {
for (int j = l[x]; j <= r[x]; j++) {
tr.update(id[j], -1);
}
}
};
function<void(int, int, int)> solveG = [&](int x, int fa, int keep) {
cerr << "Calling solveG, x = " << x << ", fa = " << fa << ", keep = " << keep << endl;
for (auto y : g[x]) {
if (y != fa && y != ls[x]) {
solveG(y, x, 0);
}
}
if (ls[x] != -1) {
solveG(ls[x], x, 1);
}
for (auto y : g[x]) {
if (y == fa || y == ls[x]) continue;
for (int j = l[y]; j <= r[y]; j++) tr.update(id[j], -1);
}
tr.update(x, -1);
G[x] = tr.query(x);
cerr << "Writing G[x] = " << G[x] << endl;
if (!keep) {
for (int j = l[x]; j <= r[x]; j++) {
tr.update(id[j], 1);
}
}
};
solveF(1, 0, 1);
solveG(1, 0, 1);
fill(tr.begin(), tr.end(), 0);
vector<long long> f(n + 1);
function<void(int, int)> get = [&](int x, int fa) {
tr.update(x, 1);
for (auto y : g[x]) {
if (y == fa) {
continue;
}
get(y, x);
}
f[1] += dep[x] - tr.query(x);
tr.update(x, -1);
};
function<void(int, int)> ans = [&](int x, int fa) {
f[x] += f[fa] - F[x] + G[x];
// 父亲答案 - 当前子树比父亲小的元素个数 + 非当前子树比当前元素小的元素个数
// 考虑当前元素的ans3一定也是父亲的ans
// 考虑当前元素的ans2要么是父亲的ans3要么是其他子树中比当前元素小的元素
// 考虑父亲的ans3一定可以是当前元素的ans
// 考虑父亲的ans2可能是当前子树比父亲小的元素需要排除。
for (auto y : g[x]) {
if (y == fa) {
continue;
}
ans(y, x);
}
};
get(1, 0);
ans(1, 0);
for (int i = 1; i <= n; i++) {
cout << F[i] << ' ';
}
cout << endl;
for (int i = 1; i <= n; i++) {
cout << G[i] << ' ';
}
cout << endl;
for (int i = 1; i <= n; i++) {
cout << f[i] << ' ';
}
return 0;
}