이 제출은 이전 버전의 oj.uz에서 채점하였습니다. 현재는 제출 당시와는 다른 서버에서 채점을 하기 때문에, 다시 제출하면 결과가 달라질 수도 있습니다.
#include "catdog.h"
#include <bits/stdc++.h>
using namespace std;
const int INF = 1e7;
const int MAXN = 1e5 + 5;
class Node {
public:
int par, ch[2], state;
array<int, 2> sum; // sum of dp of light children
array<array<int, 2>, 2> dp; // merged values on chain (dp[i][j] = start from color i, ending at color j)
Node() {
par = ch[0] = ch[1] = 0;
state = 2;
sum = {0, 0};
dp[0] = {0, INF};
dp[1] = {INF, 0};
}
void ChangeState(int t) {
state = t;
}
int Answer() {
return min({dp[0][0], dp[0][1], dp[1][0], dp[1][1]});
}
};
int root;
Node tree[MAXN];
int sub[MAXN];
int heavy[MAXN];
vector<int> adj[MAXN];
bool IsChainRoot(int u) {
return tree[tree[u].par].ch[0] != u && tree[tree[u].par].ch[1] != u;
}
void Reupdate(int u) { // array<int, 2>{1, 0}});
tree[u].dp[0] = {tree[u].sum[0], INF};
tree[u].dp[1] = {INF, tree[u].sum[1]};
if (tree[u].state == 0) {
tree[u].dp[0][0] = INF;
} else if (tree[u].state == 1) {
tree[u].dp[1][1] = INF;
}
if (tree[u].ch[1]) {
array<array<int, 2>, 2> res;
res[0] = res[1] = {INF, INF};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
for (int l = 0; l < 2; l++) {
res[i][j] = min(res[i][j],
(k != l) + tree[u].dp[i][k] + tree[tree[u].ch[1]].dp[l][j]);
}
}
}
}
tree[u].dp = res;
}
if (tree[u].ch[0]) {
array<array<int, 2>, 2> res;
res[0] = res[1] = {INF, INF};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
for (int l = 0; l < 2; l++) {
res[i][j] = min(res[i][j],
(k != l) + tree[tree[u].ch[0]].dp[i][k] + tree[u].dp[l][j]);
}
}
}
}
tree[u].dp = res;
}
}
void UpdateSum(int p, int u, int sgn) {
tree[p].sum[0] += sgn * min({tree[u].dp[0][0], tree[u].dp[0][1],
tree[u].dp[1][0] + 1, tree[u].dp[1][1] + 1});
tree[p].sum[1] += sgn * min({tree[u].dp[1][0], tree[u].dp[1][1],
tree[u].dp[0][0] + 1, tree[u].dp[0][1] + 1});
}
int Update(int u, int type) {
tree[u].ChangeState(type);
for (; u; u = tree[u].par) {
if (tree[u].par && IsChainRoot(u)) {
UpdateSum(tree[u].par, u, -1);
Reupdate(u);
UpdateSum(tree[u].par, u, +1);
} else {
Reupdate(u);
}
}
return tree[root].Answer();
}
void DfsInit(int u, int p) {
if (p) {
adj[u].erase(find(begin(adj[u]), end(adj[u]), p));
}
sub[u] = 1;
for (auto &v : adj[u]) {
DfsInit(v, u);
sub[u] += sub[v];
if (!heavy[u] || sub[heavy[u]] < sub[v]) {
heavy[u] = v;
}
}
}
int Build(int l, int r, const vector<int> &chain) {
if (l > r) return 0;
int all = 0, cur = 0, mid;
for (int i = l; i <= r; i++) all += sub[chain[i]];
for (mid = l; mid <= r; mid++) {
cur += sub[chain[mid]];
if (cur * 2 > all) {
break;
}
}
int id = chain[mid];
tree[id].ch[0] = Build(l, mid - 1, chain);
tree[id].ch[1] = Build(mid + 1, r, chain);
if (tree[id].ch[0]) tree[tree[id].ch[0]].par = id;
if (tree[id].ch[1]) tree[tree[id].ch[1]].par = id;
Reupdate(id);
return id;
}
int Construct(int u) {
for (int i = u; i; i = heavy[i]) {
for (auto v : adj[i]) {
if (v != heavy[i]) {
int r = Construct(v);
tree[r].par = i;
UpdateSum(i, r, +1);
}
}
}
static vector<int> chain; chain.clear();
for (int i = u; i; i = heavy[i]) {
chain.emplace_back(i);
}
for (int i = 0; i + 1 < (int) chain.size(); i++) {
sub[chain[i]] -= sub[chain[i + 1]];
}
return Build(0, int(chain.size()) - 1, chain);
}
void initialize(int N, vector<int> A, vector<int> B) {
for (int i = 0; i + 1 < N; i++) {
adj[A[i]].emplace_back(B[i]);
adj[B[i]].emplace_back(A[i]);
}
DfsInit(1, 0);
root = Construct(1);
}
int cat(int v) {
return Update(v, 0);
}
int dog(int v) {
return Update(v, 1);
}
int neighbor(int v) {
return Update(v, 2);
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |