Submission #933968

#TimeUsernameProblemLanguageResultExecution timeMemory
933968boris_mihovTourism (JOI23_tourism)C++17
100 / 100
3221 ms43676 KiB
#include <algorithm> #include <iostream> #include <numeric> #include <cassert> #include <vector> #include <stack> #include <cmath> #pragma GCC optimize ("O3") #pragma GCC target ("sse4") typedef long long llong; const int MAXN = 100000 + 10; const int MAXLOG = 18; const int INF = 1e9; int n, m, q; int in[MAXN]; int out[MAXN]; int globalCost; bool isInC[MAXN]; std::vector <int> notInC; std::vector <int> inTimes; int cnt[2 * MAXN]; int c[MAXN]; struct LinkedList { struct Sparse { int sparse[MAXLOG][2 * MAXN]; std::vector <int> tour; int getLog[2 * MAXN]; int depth[MAXN]; int cmp(int x, int y) { if (depth[x] < depth[y]) return x; else return y; } void build(std::vector <int> _tour, int dep[]) { tour = _tour; for (int i = 1 ; i <= n ; ++i) { depth[i] = dep[i]; } for (int i = 1 ; i < tour.size() ; ++i) { sparse[0][i] = tour[i]; } for (int lg = 1 ; (1 << lg) <= tour.size() ; ++lg) { for (int i = 1 ; i + (1 << lg) - 1 < tour.size() ; ++i) { sparse[lg][i] = cmp(sparse[lg - 1][i], sparse[lg - 1][i + (1 << lg - 1)]); } } for (int i = 1 ; i <= tour.size() ; ++i) { getLog[i] = getLog[i - 1]; if ((1 << getLog[i] + 1) < i) getLog[i]++; } } int findLCA(int l, int r) { int lg = getLog[r - l + 1]; return cmp(sparse[lg][l], sparse[lg][r - (1 << lg) + 1]); } int findDist(int u, int v) { if (in[u] > in[v]) { std::swap(u, v); } return depth[u] + depth[v] - 2 * depth[findLCA(in[u], in[v])]; } }; struct RollElementCnt { int idx; int time; int value; }; struct RollElement { int idx; int value; }; int answer; int prev[2 * MAXN]; int next[2 * MAXN]; int prev2[2 * MAXN]; int next2[2 * MAXN]; int answer2; std::stack <RollElement> stNext; std::stack <RollElement> stPrev; std::stack <RollElementCnt> stCnt; std::stack <int> stAnswer; std::stack <int> stTime; std::vector <int> tour; Sparse sparse; int timer; void build(std::vector <int> _tour, int depth[]) { tour = _tour; sparse.build(tour, depth); } void fix() { int ptr = 0; for (int i = 0 ; i <= tour.size() ; ++i) { while (inTimes[ptr] <= i) { ptr++; } next[i] = inTimes[ptr]; } ptr = inTimes.size() - 1; for (int i = tour.size() ; i >= 0 ; --i) { while (inTimes[ptr] >= i) { ptr--; } prev[i] = inTimes[ptr]; } std::fill(cnt, cnt + 1 + 2 * n, 0); for (int i = 1 ; i <= m ; ++i) { cnt[in[c[i]]]++; } answer = 2 * n - 2 - sparse.findDist(tour[next[0]], tour[prev[tour.size()]]); timer = 0; for (const int &i : notInC) { remove(in[i]); } for (int i = 0 ; i <= tour.size() + 1 ; ++i) { prev2[i] = prev[i]; next2[i] = next[i]; } answer2 = answer; } void rebuild() { while (stNext.size()) { stNext.pop(); } while (stPrev.size()) { stPrev.pop(); } while (stCnt.size()) { stCnt.pop(); } while (stAnswer.size()) { stAnswer.pop(); } while (stTime.size()) { stTime.pop(); } std::fill(cnt, cnt + 1 + 2 * n, 0); for (int i = 1 ; i <= m ; ++i) { cnt[in[c[i]]]++; } timer = 0; for (int i = 0 ; i <= tour.size() + 1 ; ++i) { prev[i] = prev2[i]; next[i] = next2[i]; } answer = answer2; } void roll(int to) { while (stCnt.size() && stCnt.top().time > to) { cnt[stCnt.top().idx] = stCnt.top().value; stCnt.pop(); } while (stTime.size() && stTime.top() > to) { next[stNext.top().idx] = stNext.top().value; prev[stPrev.top().idx] = stPrev.top().value; answer = stAnswer.top(); stNext.pop(); stTime.pop(); stPrev.pop(); stAnswer.pop(); } } void remove(int idx) { timer++; stCnt.push({idx, timer, cnt[idx]}); cnt[idx]--; if (cnt[idx] > 0) { return; } int l = prev[idx]; int r = next[idx]; stTime.push(timer); stAnswer.push(answer); stNext.push({l, next[l]}); stPrev.push({r, prev[r]}); if (l > 0) answer -= sparse.findDist(tour[l], tour[idx]); if (r < tour.size()) answer -= sparse.findDist(tour[idx], tour[r]); if (l > 0 && r < tour.size()) answer += sparse.findDist(tour[l], tour[r]); next[l] = r; prev[r] = l; getAnswer(); } int getAnswer() { int res = answer; res += sparse.findDist(tour[next[0]], tour[prev[tour.size()]]); return res / 2 + 1; } }; int bucketSize; LinkedList list; struct Query { int l, r; int idx; friend bool operator < (const Query &a, const Query &b) { if (a.l / bucketSize != b.l / bucketSize) return a.l < b.l; return a.r > b.r; } }; int depth[MAXN]; int answer[MAXN]; std::vector <int> tour; std::vector <int> g[MAXN]; Query query[MAXN]; void buildDFS(int node, int par) { depth[node] = depth[par] + 1; in[node] = tour.size(); tour.push_back(node); for (const int &u : g[node]) { if (u == par) { continue; } buildDFS(u, node); tour.push_back(node); } out[node] = tour.size(); } void solve() { bucketSize = 2 * sqrt(m) + 1; tour.push_back(0); buildDFS(1, 0); for (int i = 1 ; i <= n ; ++i) { inTimes.push_back(in[i]); } inTimes.push_back(-1); inTimes.push_back(0); inTimes.push_back(tour.size()); inTimes.push_back(tour.size() + 1); std::sort(inTimes.begin(), inTimes.end()); for (int i = 1 ; i <= m ; ++i) { isInC[c[i]] = true; } for (int i = 1 ; i <= n ; ++i) { if (!isInC[i]) { notInC.push_back(i); } } list.build(tour, depth); list.fix(); int lPtr = 1; int rPtr = m; int lastBucket = -1; std::sort(query + 1, query + 1 + q); for (int i = 1 ; i <= q ; ++i) { int qL = query[i].l; int qR = query[i].r; if (qL / bucketSize != lastBucket) { lPtr = 1; rPtr = m; list.rebuild(); lastBucket = qL / bucketSize; while (lPtr / bucketSize != lastBucket) { list.remove(in[c[lPtr]]); lPtr++; } } while (rPtr > qR) { list.remove(in[c[rPtr]]); rPtr--; } int rollTo = list.timer; int beforeL = lPtr; while (lPtr < qL) { list.remove(in[c[lPtr]]); lPtr++; } answer[query[i].idx] = list.getAnswer(); lPtr = beforeL; list.getAnswer(); list.roll(rollTo); list.getAnswer(); } } void input() { std::cin >> n >> m >> q; for (int i = 1 ; i < n ; ++i) { int u, v; std::cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } for (int i = 1 ; i <= m ; ++i) { std::cin >> c[i]; } for (int i = 1 ; i <= q ; ++i) { std::cin >> query[i].l >> query[i].r; query[i].idx = i; } } void print() { for (int i = 1 ; i <= q ; ++i) { std::cout << answer[i] << '\n'; } } void fastIOI() { std::ios_base :: sync_with_stdio(0); std::cout.tie(nullptr); std::cin.tie(nullptr); } int main() { fastIOI(); input(); solve(); print(); return 0; }

Compilation message (stderr)

tourism.cpp: In member function 'void LinkedList::Sparse::build(std::vector<int>, int*)':
tourism.cpp:50:32: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   50 |             for (int i = 1 ; i < tour.size() ; ++i)
      |                              ~~^~~~~~~~~~~~~
tourism.cpp:55:41: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   55 |             for (int lg = 1 ; (1 << lg) <= tour.size() ; ++lg)
      |                               ~~~~~~~~~~^~~~~~~~~~~~~~
tourism.cpp:57:52: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   57 |                 for (int i = 1 ; i + (1 << lg) - 1 < tour.size() ; ++i)
      |                                  ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
tourism.cpp:59:88: warning: suggest parentheses around '-' inside '<<' [-Wparentheses]
   59 |                     sparse[lg][i] = cmp(sparse[lg - 1][i], sparse[lg - 1][i + (1 << lg - 1)]);
      |                                                                                     ~~~^~~
tourism.cpp:63:32: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   63 |             for (int i = 1 ; i <= tour.size() ; ++i)
      |                              ~~^~~~~~~~~~~~~~
tourism.cpp:66:37: warning: suggest parentheses around '+' inside '<<' [-Wparentheses]
   66 |                 if ((1 << getLog[i] + 1) < i) getLog[i]++;
      |                           ~~~~~~~~~~^~~
tourism.cpp: In member function 'void LinkedList::fix()':
tourism.cpp:126:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  126 |         for (int i = 0 ; i <= tour.size() ; ++i)
      |                          ~~^~~~~~~~~~~~~~
tourism.cpp:161:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  161 |         for (int i = 0 ; i <= tour.size() + 1 ; ++i)
      |                          ~~^~~~~~~~~~~~~~~~~~
tourism.cpp: In member function 'void LinkedList::rebuild()':
tourism.cpp:204:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  204 |         for (int i = 0 ; i <= tour.size() + 1 ; ++i)
      |                          ~~^~~~~~~~~~~~~~~~~~
tourism.cpp: In member function 'void LinkedList::remove(int)':
tourism.cpp:252:15: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  252 |         if (r < tour.size()) answer -= sparse.findDist(tour[idx], tour[r]);
      |             ~~^~~~~~~~~~~~~
tourism.cpp:253:24: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  253 |         if (l > 0 && r < tour.size()) answer += sparse.findDist(tour[l], tour[r]);
      |                      ~~^~~~~~~~~~~~~
#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...