This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
using lint = long long;
const lint INF = 1e18;
const lint MOD = 1e9 + 7;
class SegTree {
public:
int sz;
vector<int> cnt;
vector<lint> tree;
vector<lint> lazy;
SegTree(int sz) : sz(sz), cnt(2 * sz), tree(2 * sz), lazy(2 * sz) {
Build(1, 0, sz - 1);
}
void Build(int n, int tl, int tr) {
if (tl == tr) {
cnt[n] = 1;
tree[n] = 0;
lazy[n] = 0;
return;
}
int md = (tl + tr) / 2;
int z = n + 2 * (md - tl + 1);
Build(n + 1, tl, md);
Build(z, md + 1, tr);
Pull(n, n + 1, z);
}
void Pull(int n, int lc, int rc) {
cnt[n] = cnt[lc] + cnt[rc];
tree[n] = tree[lc] + tree[rc];
if (cnt[n] > 1) {
tree[n] %= MOD;
}
}
void Apply(int n, lint x) {
tree[n] += cnt[n] * x;
lazy[n] += x;
if (cnt[n] > 1) {
tree[n] %= MOD;
}
}
void Push(int n, int lc, int rc) {
Apply(lc, lazy[n]);
Apply(rc, lazy[n]);
lazy[n] = 0;
}
void Update(int n, int tl, int tr, int l, int r, lint x) {
if (l > tr || tl > r || tl > tr || l > r) return;
if (l <= tl && tr <= r) return Apply(n, x);
int md = (tl + tr) / 2;
int z = n + 2 * (md - tl + 1);
Push(n, n + 1, z);
Update(n + 1, tl, md, l, r, x);
Update(z, md + 1, tr, l, r, x);
Pull(n, n + 1, z);
}
void Update(int l, int r, lint x) {
Update(1, 0, sz - 1, l, r, x);
}
lint Query(int p) {
int n = 1, tl = 0, tr = sz - 1;
while (tl != tr) {
int md = (tl + tr) / 2;
int z = n + 2 * (md - tl + 1);
Push(n, n + 1, z);
if (p <= md) {
n = n + 1;
tr = md;
} else {
n = z;
tl = md + 1;
}
}
assert(tl == tr);
return tree[n];
}
lint Query() {
return tree[1];
}
};
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int N;
cin >> N;
vector<int> st(N);
vector<int> ist(N);
vector<int> siz(N);
vector<int> par(N);
vector<int> root(N);
vector<int> depth(N);
vector<vector<int>> adj(N);
par[0] = -1;
for (int i = 1; i < N; i++) {
cin >> par[i];
adj[par[i]].emplace_back(i);
}
const auto DfsInit = [&](const auto &self, int u) -> void {
siz[u] = 1;
for (auto &v : adj[u]) {
depth[v] = depth[u] + 1;
self(self, v);
siz[u] += siz[v];
if (siz[v] > siz[adj[u][0]]) {
swap(v, adj[u][0]);
}
}
};
const auto DfsHld = [&](const auto &self, int u) -> void {
static int timer = 0;
st[u] = timer++;
ist[st[u]] = u;
for (auto v : adj[u]) {
root[v] = v == adj[u][0] ? root[u] : v;
self(self, v);
}
};
DfsInit(DfsInit, 0);
DfsHld(DfsHld, 0);
// Complexity by Link-Cut Tree Heavy-Light analysis
// Keep segment tree, with dp[v] on position v
// Update link-cut style on HLD
// Time: O((N + Q) log^2 N).
set<int> chain;
for (int i = 0; i < N; i++) {
chain.emplace(st[i]);
}
const auto ModifyChain = [&](int u, int sgn) {
if (sgn == -1) {
chain.erase(chain.find(st[u]));
} else if (sgn == +1) {
chain.emplace(st[u]);
}
};
SegTree dp_1(N);
SegTree dp_2(N);
vector<int> prefer(N, -1);
vector<lint> weight(N);
const auto Update = [&](const auto &self, int prv) -> void {
if (prv == 0) return;
int u = par[prv];
lint newdp = dp_1.Query(st[prv]) + weight[prv];
if (newdp <= dp_2.Query(st[u])) {
// do nothing
} else if (dp_2.Query(st[u]) < newdp && newdp <= dp_1.Query(st[u])) {
dp_2.Update(st[u], st[u], newdp - dp_2.Query(st[u]));
} else if (dp_1.Query(st[u]) < newdp) {
lint dp1 = dp_1.Query(st[u]);
lint dp2 = dp_2.Query(st[u]);
int head = ist[*prev(chain.upper_bound(st[u]))];
assert(root[u] == root[head]);
if (prefer[u] == prv) {
dp_1.Update(st[head], st[u], newdp - dp1);
return self(self, head);
}
if (prefer[u] != -1) {
// insert prefer[u] as head chain
ModifyChain(prefer[u], +1);
prefer[u] = -1;
}
prefer[u] = prv;
if (root[u] == root[prv]) {
// delete prv as head chain
ModifyChain(prv, -1);
}
dp_2.Update(st[u], st[u], dp1 - dp2);
dp_1.Update(st[head], st[u], newdp - dp1);
return self(self, head);
}
};
const auto Print = [&]() {
for (int i = 0; i < N; i++) {
cout << i << ' ' << dp_1.Query(st[i]) << ' ' << dp_2.Query(st[i]) << '\n';
}
cout << '\n';
};
for (int i = 1; i < N; i++) {
int w;
cin >> w;
weight[i] += w;
Update(Update, i);
}
cout << (dp_1.Query() + dp_2.Query()) % MOD << '\n';
int Q;
cin >> Q;
while (Q--) {
int u, w;
cin >> u >> w;
weight[u] += w;
Update(Update, u);
cout << (dp_1.Query() + dp_2.Query()) % MOD << '\n';
// Print();
}
return 0;
}
Compilation message (stderr)
arboras.cpp: In function 'int main()':
arboras.cpp:200:14: warning: variable 'Print' set but not used [-Wunused-but-set-variable]
200 | const auto Print = [&]() {
| ^~~~~
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |