이 제출은 이전 버전의 oj.uz에서 채점하였습니다. 현재는 제출 당시와는 다른 서버에서 채점을 하기 때문에, 다시 제출하면 결과가 달라질 수도 있습니다.
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 16;
int n, q, W, u, v;
ll w, result;
vector < pair <int, ll> > adj[N];
vector <int> id[N];
/*
4 3 2000
1 2 100
2 3 1000
2 4 1000
2 1030
1 1020
1 890
*/
/*
10 10 10000
1 9 1241
5 6 1630
10 5 1630
2 6 853
10 1 511
5 3 760
8 3 1076
4 10 1483
7 10 40
8 2051
5 6294
5 4168
7 1861
0 5244
6 5156
3 3001
8 5267
5 3102
8 3623
*/
ll a[N];
int h[N], par[N], sz[N], edge[N];
int chainHead[N], chainId[N], chainArr[N], pos[N], curPos = 1, curChain = 1;
void dfs(int k, int p) {
sz[k] = 1;
int i = -1;
for (auto v : adj[k]) {
i++;
if (v.first == p) {
continue;
}
edge[id[k][i]] = v.first;
a[v.first] = v.second;
h[v.first] = h[k] + 1;
par[v.first] = k;
dfs(v.first, k);
sz[k] += sz[v.first];
}
}
void hld(int k, int p) {
if (!chainHead[curChain]) {
chainHead[curChain] = k;
}
chainId[k] = curChain;
pos[k] = curPos;
chainArr[curPos] = k;
curPos++;
int heaviest = 0;
for (auto v : adj[k]) {
if (v.first == p) {
continue;
}
if (heaviest == 0 || sz[v.first] > sz[heaviest]) {
heaviest = v.first;
}
}
if (heaviest) {
hld(heaviest, k);
}
for (auto v : adj[k]) {
if (v.first == p || v.first == heaviest) {
continue;
}
curChain++;
hld(v.first, k);
}
}
int lca(int u, int v) {
while (chainId[u] != chainId[v]) {
if (chainId[u] > chainId[v]) {
u = par[chainHead[chainId[u]]];
}
else {
v = par[chainHead[chainId[v]]];
}
}
if (h[u] < h[v]) {
return u;
}
return v;
}
ll segmentTree[4 * N];
void build(int k, int l, int r) {
if (l == r) {
segmentTree[k] = a[chainArr[l]];
return;
}
int mid = (l + r) / 2;
build(2 * k, l, mid);
build(2 * k + 1, mid + 1, r);
segmentTree[k] = segmentTree[2 * k] + segmentTree[2 * k + 1];
}
void update(int k, int l, int r, int x, ll y) {
if (l > x || x > r) {
return;
}
if (l == r) {
segmentTree[k] = y;
return;
}
int mid = (l + r) / 2;
update(2 * k, l, mid, x, y);
update(2 * k + 1, mid + 1, r, x, y);
segmentTree[k] = segmentTree[2 * k] + segmentTree[2 * k + 1];
}
ll get(int k, int l, int r, int x, int y) {
if (l > y || x > r) {
return 0;
}
if (l >= x && r <= y) {
return segmentTree[k];
}
int mid = (l + r) / 2;
return get(2 * k, l, mid, x, y) + get(2 * k + 1, mid + 1, r, x, y);
}
void updateTree(int id, ll val) {
update(1, 1, curPos, pos[edge[id]], val);
}
ll getTree(int u, int v) {
int LCA = lca(u, v);
ll ans = 0;
while (chainId[u] != chainId[LCA]) {
ans = get(1, 1, curPos, pos[chainHead[chainId[u]]], pos[u]) + ans;
u = par[chainHead[chainId[u]]];
}
while (chainId[v] != chainId[LCA]) {
ans = get(1, 1, curPos, pos[chainHead[chainId[v]]], pos[v]) + ans;
v = par[chainHead[chainId[v]]];
}
if (h[u] < h[v]) {
ans = get(1, 1, curPos, pos[u] + 1, pos[v]) + ans;
}
else {
ans = get(1, 1, curPos, pos[v] + 1, pos[u]) + ans;
}
return ans;
}
int parCd[N], szCd[N];
bool visited[N];
void countChild(int k, int p) {
szCd[k] = 1;
for (auto v : adj[k]) {
if (visited[v.first] || v.first == p) {
continue;
}
countChild(v.first, k);
szCd[k] += szCd[v.first];
}
}
int findCentroid(int k, int p, int treeSz) {
for (auto v : adj[k]) {
if (visited[v.first] || v.first == p) {
continue;
}
if (sz[v.first] > treeSz / 2) {
return findCentroid(v.first, k, treeSz);
}
}
return k;
}
void cd(int k, int p) {
countChild(k, k);
int centroid = findCentroid(k, k, sz[k]);
visited[centroid] = true;
parCd[centroid] = p;
for (auto v : adj[centroid]) {
if (!visited[v.first]) {
cd(v.first, centroid);
}
}
}
multiset < pair <ll, int> > s[N];
void updateCentroid(int k) {
int v = k, p = k;
while (v) {
bool sameSub = false;
for (auto x : s[v]) {
if (x.second != p) {
continue;
}
sameSub = true;
ll dist = getTree(k, v);
if (dist > x.first) {
s[v].erase(x);
s[v].insert({dist, p});
break;
}
}
if (!sameSub) {
s[v].insert({getTree(k, v), p});
if (s[v].size() > 2) {
s[v].erase(s[v].begin());
}
}
p = v;
v = parCd[v];
}
}
ll getCentroid(int k) {
ll ans = 0;
int v = k, p = k;
while (v) {
for (auto x : s[v]) {
if (x.second != p) {
ans = max(ans, x.first + getTree(k, v));
}
}
p = v;
v = parCd[v];
}
return ans;
}
pair <int, int> e[N];
void removeCentroid(int k) {
int v = k, p = k;
while (v) {
pair <ll, int> val = {getTree(k, v), p};
if (s[v].find(val) != s[v].end()) {
s[v].erase(s[v].find(val));
}
p = v;
v = parCd[v];
}
}
void updateAll(int id, ll val) {
u = e[id].first;
v = e[id].second;
removeCentroid(u);
removeCentroid(v);
updateTree(id, val);
updateCentroid(u);
updateCentroid(v);
}
int main() {
ios_base :: sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> q >> W;
for (int i = 1; i < n; i++) {
cin >> u >> v >> w;
adj[u].push_back({v, w});
adj[v].push_back({u, w});
id[u].push_back(i);
id[v].push_back(i);
e[i] = {u, v};
}
dfs(1, 1);
hld(1, 1);
build(1, 1, curPos);
cd(1, 0);
for (int i = 1; i <= n; i++) {
updateCentroid(i);
}
while (q--) {
int d, f;
cin >> d >> f;
d = 1 + (d + result) % (n - 1);
f = (f + result) % W;
updateAll(d, f);
result = 0;
for (int i = 1; i <= n; i++) {
result = max(result, getCentroid(i));
}
cout << result << "\n";
}
return 0;
}
# | 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... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |