Submission #1303096

#TimeUsernameProblemLanguageResultExecution timeMemory
1303096tonytung_123Tourism (JOI23_tourism)C++20
28 / 100
5097 ms46196 KiB
#include <bits/stdc++.h> using namespace std; #define task "Tourism" using pii = pair<int,int>; using ll = long long; struct Query { int l, r, i; long long ord; }; const int N = 100000 + 5; const int LG = 20; // enough for 2*N <= 2e5 vector<int> ad[N]; int n, m, q; int tin[N], depthArr[N], c[200000+5], cnt[N], ans[N]; pair<int,int> rmq[LG+1][2*N]; int timer = 0; set<pii> nodes; long long tot = 0; Query que[200000+5]; int LOG2[2*N]; inline long long hilbertOrder(int x, int y, int pow=21, int rotate=0) { if (pow == 0) return 0; int hpow = 1 << (pow-1); int seg = (x < hpow) ? ( (y < hpow) ? 0 : 3 ) : ( (y < hpow) ? 1 : 2 ); const int rotateDelta[4] = {3,0,0,1}; int nx = x & (hpow-1), ny = y & (hpow-1); int nrot = (rotate + rotateDelta[seg]) & 3; long long subSquareSize = 1LL << (2*pow - 2); long long ans = seg * subSquareSize + hilbertOrder(nx, ny, pow-1, nrot); if (seg == 1) { swap(nx, ny); } else if (seg == 2) { nx = hpow-1 - nx; ny = hpow-1 - ny; } else if (seg == 3) { swap(nx, ny); nx = hpow-1 - nx; ny = hpow-1 - ny; } return ans; } void dfs(int u, int p) { tin[u] = ++timer; rmq[0][timer] = { depthArr[u], u }; for (int v : ad[u]) { if (v == p) continue; depthArr[v] = depthArr[u] + 1; dfs(v, u); // after returning to u, push u again (standard euler tour for RMQ LCA) rmq[0][++timer] = { depthArr[u], u }; } } inline int lca(int u, int v) { int l = tin[u], r = tin[v]; if (l > r) swap(l, r); int k = LOG2[r - l + 1]; auto a = rmq[k][l]; auto b = rmq[k][r - (1<<k) + 1]; return (a.first <= b.first ? a.second : b.second); } inline int dist(int u, int v) { int w = lca(u,v); return depthArr[u] + depthArr[v] - 2*depthArr[w]; } pii find_neighbors(int u) { auto it = nodes.lower_bound({tin[u], -1}); pii res; if (it == nodes.end()) { --it; res.first = it->second; res.second = nodes.begin()->second; } else if (it == nodes.begin()) { res.first = it->second; res.second = nodes.rbegin()->second; } else { res.first = it->second; --it; res.second = it->second; } return res; } inline void addNode(int u) { if (++cnt[u] != 1) return; if (nodes.empty()) { nodes.insert({tin[u], u}); return; } if (nodes.size() == 1) { int v = nodes.begin()->second; tot += 2LL * dist(u, v); nodes.insert({tin[u], u}); return; } auto pr = find_neighbors(u); tot += dist(pr.first, u) + dist(u, pr.second) - dist(pr.first, pr.second); nodes.insert({tin[u], u}); } inline void delNode(int u) { if (--cnt[u] != 0) return; if (nodes.size() == 1) { nodes.erase(nodes.find({tin[u], u})); return; } if (nodes.size() == 2) { nodes.erase(nodes.find({tin[u], u})); tot = 0; return; } // remove then fix tot using neighbor pair auto it = nodes.find({tin[u], u}); // get neighbors BEFORE erasing: prev and next in cyclic order auto itNext = next(it); if (itNext == nodes.end()) itNext = nodes.begin(); auto itPrev = (it == nodes.begin() ? prev(nodes.end()) : prev(it)); int v1 = itPrev->second; int v2 = itNext->second; tot -= dist(v1, u) + dist(u, v2) - dist(v1, v2); nodes.erase(it); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); if (fopen(task".inp", "r")) { freopen(task".inp", "r", stdin); freopen(task".out", "w", stdout); } cin >> n >> m >> q; for (int i = 1; i <= n; ++i) ad[i].clear(); for (int i = 1; i < n; ++i) { int u,v; cin >> u >> v; ad[u].push_back(v); ad[v].push_back(u); } timer = 0; depthArr[1] = 0; dfs(1, 0); int M = timer; // length of euler tour // precompute logs LOG2[1] = 0; for (int i = 2; i <= M; ++i) LOG2[i] = LOG2[i/2] + 1; // build sparse table only up to M for (int j = 1; (1<<j) <= M; ++j) { int len = (1<<j); for (int i = 1; i + len - 1 <= M; ++i) { auto &a = rmq[j-1][i]; auto &b = rmq[j-1][i + (1<<(j-1))]; rmq[j][i] = (a.first <= b.first ? a : b); } } for (int i = 1; i <= m; ++i) cin >> c[i]; for (int i = 1; i <= q; ++i) { cin >> que[i].l >> que[i].r; que[i].i = i; que[i].ord = hilbertOrder(que[i].l, que[i].r, 21); } sort(que+1, que+q+1, [](const Query &a, const Query &b){ return a.ord < b.ord; }); int L = 1, R = 0; // clean global state nodes.clear(); fill(cnt, cnt+n+1, 0); tot = 0; for (int idx = 1; idx <= q; ++idx) { int ql = que[idx].l, qr = que[idx].r; while (L > ql) addNode(c[--L]); while (R < qr) addNode(c[++R]); while (L < ql) delNode(c[L++]); while (R > qr) delNode(c[R--]); ans[que[idx].i] = (int)(tot/2 + 1); } for (int i = 1; i <= q; ++i) cout << ans[i] << '\n'; return 0; }

Compilation message (stderr)

tourism.cpp: In function 'int main()':
tourism.cpp:128:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  128 |         freopen(task".inp", "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
tourism.cpp:129:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  129 |         freopen(task".out", "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...