Advertisement
Jakube

Untitled

Jun 17th, 2020
1,961
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.69 KB | None | 0 0
  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. #define _ ios_base::sync_with_stdio(0);cin.tie(0);
  6.  
  7. typedef long long ll;
  8. typedef pair<int, int> ii;
  9.  
  10. const int INF = 0x3f3f3f3f;
  11. const ll LINF = 0x3f3f3f3f3f3f3f3fll;
  12.  
  13. chrono::time_point<chrono::high_resolution_clock> beg;
  14.  
  15. void reset_time() {
  16.     beg = chrono::high_resolution_clock::now();
  17. }
  18.  
  19. double get_time() {
  20.     auto end = chrono::high_resolution_clock::now();
  21.     chrono::duration<double> elapsed = end - beg;
  22.     return elapsed.count();
  23. }
  24.  
  25. int n;
  26. std::vector<std::vector<int>> adj;
  27.  
  28. int block_size, block_cnt;
  29. std::vector<int> first_visit;
  30. std::vector<int> euler_tour;
  31. std::vector<int> height;
  32. std::vector<int> log_2;
  33. std::vector<std::vector<int>> st;
  34. std::vector<std::vector<std::vector<int>>> blocks;
  35. std::vector<int> block_mask;
  36.  
  37. void dfs(int v, int p, int h) {
  38.     first_visit[v] = euler_tour.size();
  39.     euler_tour.push_back(v);
  40.     height[v] = h;
  41.    
  42.     for (int u : adj[v]) {
  43.         if (u == p)
  44.             continue;
  45.         dfs(u, v, h + 1);
  46.         euler_tour.push_back(v);
  47.     }
  48. }
  49.  
  50. int min_by_h(int i, int j) {
  51.     return height[euler_tour[i]] < height[euler_tour[j]] ? i : j;
  52. }
  53.  
  54. void precompute_lca(int root) {
  55.     // get euler tour & indices of first occurences
  56.     first_visit.assign(n, -1);
  57.     height.assign(n, 0);
  58.     euler_tour.reserve(2 * n);
  59.     dfs(root, -1, 0);
  60.  
  61.     // precompute all log values
  62.     int m = euler_tour.size();
  63.     log_2.reserve(m + 1);
  64.     log_2.push_back(-1);
  65.     for (int i = 1; i <= m; i++)
  66.         log_2.push_back(log_2[i / 2] + 1);
  67.  
  68.     block_size = std::max(1, log_2[m] / 2);
  69.     block_cnt = (m + block_size - 1) / block_size;
  70.  
  71.     // precompute minimum of each block and build sparse table
  72.     st.assign(block_cnt, std::vector<int>(log_2[block_cnt] + 1));
  73.     for (int i = 0, j = 0, b = 0; i < m; i++, j++) {
  74.         if (j == block_size)
  75.             j = 0, b++;
  76.         if (j == 0 || min_by_h(i, st[b][0]) == i)
  77.             st[b][0] = i;
  78.     }
  79.     for (int l = 1; l <= log_2[block_cnt]; l++) {
  80.         for (int i = 0; i < block_cnt; i++) {
  81.             int ni = i + (1 << (l - 1));
  82.             if (ni >= block_cnt)
  83.                 st[i][l] = st[i][l-1];
  84.             else
  85.                 st[i][l] = min_by_h(st[i][l-1], st[ni][l-1]);
  86.         }
  87.     }
  88.  
  89.     // precompute mask for each block
  90.     block_mask.assign(block_cnt, 0);
  91.     for (int i = 0, j = 0, b = 0; i < m; i++, j++) {
  92.         if (j == block_size)
  93.             j = 0, b++;
  94.         if (j > 0 && (i >= m || min_by_h(i - 1, i) == i - 1))
  95.             block_mask[b] += 1 << (j - 1);
  96.     }
  97.  
  98.     // precompute RMQ for each unique block
  99.     int possibilities = 1 << (block_size - 1);
  100.     blocks.resize(possibilities);
  101.     for (int b = 0; b < block_cnt; b++) {
  102.         int mask = block_mask[b];
  103.         if (!blocks[mask].empty())
  104.             continue;
  105.         blocks[mask].assign(block_size, std::vector<int>(block_size));
  106.         for (int l = 0; l < block_size; l++) {
  107.             blocks[mask][l][l] = l;
  108.             for (int r = l + 1; r < block_size; r++) {
  109.                 blocks[mask][l][r] = blocks[mask][l][r - 1];
  110.                 if (b * block_size + r < m)
  111.                     blocks[mask][l][r] = min_by_h(b * block_size + blocks[mask][l][r],
  112.                             b * block_size + r) - b * block_size;
  113.             }
  114.         }
  115.     }
  116. }
  117.  
  118. int lca_in_block(int b, int l, int r) {
  119.     return blocks[block_mask[b]][l][r] + b * block_size;
  120. }
  121.  
  122. int lca(int v, int u) {
  123.     int l = first_visit[v];
  124.     int r = first_visit[u];
  125.     if (l > r)
  126.         std::swap(l, r);
  127.     int bl = l / block_size;
  128.     int br = r / block_size;
  129.     if (bl == br)
  130.         return euler_tour[lca_in_block(bl, l % block_size, r % block_size)];
  131.     int ans1 = lca_in_block(bl, l % block_size, block_size - 1);
  132.     int ans2 = lca_in_block(br, 0, r % block_size);
  133.     int ans = min_by_h(ans1, ans2);
  134.     if (bl + 1 < br) {
  135.         int l = log_2[br - bl - 1];
  136.         int ans3 = st[bl+1][l];
  137.         int ans4 = st[br - (1 << l)][l];
  138.         ans = min_by_h(ans, min_by_h(ans3, ans4));
  139.     }
  140.     return euler_tour[ans];
  141. }
  142.  
  143. int main(int argc, char** argv) { _
  144.     srand(atoi(argv[1]));
  145.     cin >> n;
  146.     vector<int> v(n);
  147.     for (int& i : v) i = rand()%n;
  148.     vector<pair<int, int>> q(1000000);
  149.     for (int i = 0; i < 1000000; i++) {
  150.         int a = rand()%n, b = rand()%n;
  151.         if (a > b) swap(a, b);
  152.         q[i] = {a, b};
  153.     }
  154.  
  155.     cout << "LCA using Farach-Colton and Bender" << '\n';
  156.  
  157.     reset_time();
  158.     vector<int> parent(n, -1);
  159.     stack<int> s;
  160.     for (int i = 0; i < n; i++) {
  161.         int last = -1;
  162.         while (!s.empty() && v[s.top()] >= v[i]) {
  163.             last = s.top();
  164.             s.pop();
  165.         }
  166.         if (!s.empty())
  167.             parent[i] = s.top();
  168.         if (last >= 0)
  169.             parent[last] = i;
  170.         s.push(i);
  171.     }
  172.  
  173.     adj.resize(n);
  174.     int root = -1;
  175.     for (int i = 0; i < n; i++) {
  176.         if (parent[i] >= 0)
  177.             adj[parent[i]].push_back(i);
  178.         else
  179.             root = i;
  180.     }
  181.     precompute_lca(root);
  182.     double build_time = get_time();
  183.    
  184.     ll sum = 0;
  185.  
  186.     reset_time();
  187.     for (auto i : q) sum += v[lca(i.first, i.second)];
  188.     double query_time = get_time();
  189.  
  190.     cout << sum << '\n';
  191.     cout << int(1000*build_time) << " " << int(1000*query_time) << '\n';
  192.  
  193.     exit(0);
  194. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement