Advertisement
ec1117

Untitled

Feb 9th, 2021
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.90 KB | None | 0 0
  1. Key insight 1: Since we always end on a central, at any time our robot have to be able to reach the nearest central.
  2.  
  3. Key insight 2: Since we always start from a central, from any node u, going to the nearest central, then going back to u can't decrease the number of energy points in the battery.
  4.  
  5.  
  6. Firstly, let's do a multi-source Dijkstra from all centrals. We denote du the distance from node u to the nearest central.
  7.  
  8. Consider a fixed capacity c. Suppose that we're on node u with x energy points remaining in the battery. Note that x≤c−du.
  9.  
  10. If x<du, we can't do anything, the robot is lost because it can't reach any central anymore.
  11.  
  12. Otherwise, if x≥du, we can go to the nearest central, then go back to u, hence we can always consider than x=c−du.
  13.  
  14. This is a simple but very powerful observation that allows us to delete the battery level in states explored. Hence, we can now solve the problem in O(mlogm+qmlogn), doing binary search on answer and simple DFS for each query.
  15.  
  16.  
  17. We need to optimize this solution. Now, reaching a node u will mean reaching it with x≥du.
  18.  
  19. During exploration of nodes, the necessary and sufficient condition for being able to reach node v from u, through an edge of weight w, is that (c−du)−w≥dv, i.e. du+dv+w≤c.
  20.  
  21. Hence, if we replace the weight of each edge (u,v,w) by w′=du+dv+w, the problem is reduced to find a shortest path from ai to bi, in terms of maximum weight over edges used (which will be the capacity required by this path).
  22.  
  23. Solution 1 (offline):
  24.  
  25. Sort edges by new weight. Add them progressively, maintaining connexity with DSU.
  26.  
  27. As soon as two endpoints of a query become connected, we should put current capacity (i.e. new weight of the last edge added) as answer for this query.
  28.  
  29. To effeciently detect this, we can put tokens on endpoints of each query, and each time we do union (of DSU), we make tokens go up to the parent. If we do union by rank, each token will move at most O(logn) times.
  30.  
  31. Solution 2 (online):
  32.  
  33. Let's construct a MST of the new graph with Kruskal.
  34.  
  35. It is well-known that in this particular MST, for every pair of nodes (u,v), the only path from u to v will be a shortest path (in terms of maximum weight over the path).
  36.  
  37. Hence we just have to compute the weight of paths in a tree, which can be done with binary lifting.
  38.  
  39. These two solutions both run in O(mlogm+qlogn). Implementation of solution 1 is a bit shorter, but solution 2 can deal with online queries.
  40.  
  41. template<int SZ> struct DSU {
  42.     int parent[SZ], size[SZ];
  43.  
  44.     DSU() {
  45.         F0R(i, SZ) parent[i] = i, size[i] = 0;
  46.     }
  47.  
  48.     int get(int x) {
  49.         if (parent[x] != x) parent[x] = get(parent[x]);
  50.         return parent[x];
  51.     }
  52.  
  53.     void unify(int x, int y) {
  54.         x = get(x); y = get(y);
  55.         if (x == y) return;
  56.         if (size[x] < size[y]) swap(x, y);
  57.         if (size[x] == size[y]) size[x]++;
  58.         parent[y] = x;
  59.  
  60.     }
  61. };
  62.  
  63. vector<vpl> graph;
  64. int depth[MX], parent[MX];
  65. int K;
  66. int anc[MX][18]; ll maxVal[MX][18];
  67. ll weightDown[MX];
  68.  
  69. void dfs(int v, int p) {
  70.     if (p == -1) {
  71.         depth[v] = 0;
  72.     } else {
  73.         depth[v] = depth[p]+1;
  74.     }
  75.     parent[v] = p;
  76.     weightDown[v] = 0;
  77.  
  78.     F0R(i, sz(graph[v])) {
  79.         int nxt = graph[v][i].f;
  80.         if (nxt == p) {
  81.             weightDown[v] = graph[v][i].s;
  82.             //cout << v << " " << weightDown[v] << endl;
  83.  
  84.             continue;
  85.         }
  86.         dfs(nxt, v);
  87.     }
  88. }
  89.  
  90. void precomp() {
  91.     F0R(i, K) {
  92.         F0R(j, 18) {
  93.             anc[i][j] = -1;
  94.         }
  95.         anc[i][0] = parent[i];
  96.         maxVal[i][0] = weightDown[i];
  97.     }
  98.     FOR(j, 1, 18) {
  99.         F0R(i, K) {
  100.             if (anc[i][j-1] != -1) {
  101.                 anc[i][j] = anc[anc[i][j-1]][j-1];
  102.                 maxVal[i][j] = max(maxVal[i][j-1], maxVal[anc[i][j-1]][j-1]);
  103.             }
  104.         }
  105.     }
  106. }
  107.  
  108. ll distVal(int A, int B) {
  109.     if (depth[A] < depth[B]) {
  110.         int C = B;
  111.         B = A;
  112.         A = C;
  113.     }
  114.  
  115.     int dist = depth[A] - depth[B];
  116.     ll ans = 0;
  117.     while (dist > 0) {
  118.         F0R(i, 18) {
  119.             if (dist & (1 << i)) {
  120.                 ans = max(ans, maxVal[A][i]);
  121.                 //cout << ans << " " << maxVal[A][i] << endl;
  122.                 A = anc[A][i];
  123.                 dist -= 1 << i;
  124.             }
  125.         }
  126.     }
  127.     if (A == B) return ans;
  128.     F0Rd(j, 18) {
  129.         if (anc[A][j] != -1 && anc[A][j] != anc[B][j]) {
  130.             ans = max(ans, max(maxVal[A][j], maxVal[B][j]));
  131.             A = anc[A][j]; B = anc[B][j];
  132.         }
  133.     }
  134.     ans = max(ans, max(weightDown[A], weightDown[B]));
  135.     return ans;
  136. }
  137.  
  138. int main() {
  139.     ios_base::sync_with_stdio(0); cin.tie(0);    
  140.    
  141.     int N, M, Q; cin >> N >> M >> K >> Q;
  142.  
  143.     F0R(i, N) {
  144.         vpl blank; graph.pb(blank);
  145.     }
  146.  
  147.     F0R(i, M) {
  148.         int A, B, C; cin >> A >> B >> C;
  149.         A--; B--;
  150.         graph[A].pb({B, C});
  151.         graph[B].pb({A, C});
  152.     }
  153.  
  154.     vector<pair<ll, pi> > edges;
  155.     int owner[N]; F0R(i, N) owner[i] = -1;
  156.     ll dist[N]; F0R(i, N) dist[i] = 1000000000000000;
  157.     bool visited[N]; F0R(i, N) visited[i] = false;
  158.     F0R(i, K) visited[i] = true;
  159.     F0R(i, K) {
  160.         owner[i] = i; dist[i] = 0;
  161.     }
  162.  
  163.     priority_queue<pair<ll, pi>> q; //dist, next, owner
  164.     F0R(i, K) {
  165.         F0R(j, sz(graph[i])) {
  166.             q.push({graph[i][j].s*-1, {graph[i][j].f, i}});
  167.         }
  168.     }
  169.  
  170.     while (!q.empty()) {
  171.         pair<ll, pi> curData = q.top(); q.pop();
  172.         ll curDist = curData.f * -1;
  173.         int curOwn = curData.s.s;
  174.         int cur = curData.s.f;
  175.         if (visited[cur]) {
  176.             if (owner[cur] != curOwn) {
  177.                 edges.pb({curDist + dist[cur], {curOwn, owner[cur]}});
  178.             }
  179.             continue;
  180.         }
  181.         visited[cur] = true;
  182.         dist[cur] = curDist;
  183.         owner[cur] = curOwn;
  184.  
  185.         F0R(i, sz(graph[cur])) {
  186.            
  187.             int nxt = graph[cur][i].f;
  188.             ll nxtDist = curDist + graph[cur][i].s;
  189.             //cout << cur << " " << dist[cur] << " " << owner[cur] << " " << nxt << " " << nxtDist << endl;
  190.             q.push({nxtDist*-1, {nxt, curOwn}});
  191.         }
  192.     }
  193.  
  194.     //build MST
  195.     vector<vpl> mst;
  196.     F0R(i, K) {
  197.         vpl blank; mst.pb(blank);
  198.     }
  199.     DSU<MX> dsu;
  200.     sort(all(edges));
  201.     F0R(i, sz(edges)) {
  202.  
  203.         int A = edges[i].s.f, B = edges[i].s.s;
  204.         ll dist = edges[i].f;
  205.         //cout << A << " " << B << " " << dist << " edge" << endl;
  206.         if (dsu.get(A) != dsu.get(B)) {
  207.             dsu.unify(A, B);
  208.             mst[A].pb({B, dist});
  209.             mst[B].pb({A, dist});
  210.         }
  211.  
  212.     }
  213.     graph = mst;
  214.  
  215.     dfs(0, -1);
  216.     precomp();
  217.  
  218.     F0R(i, Q) {
  219.         int A, B; cin >> A >> B; A--; B--;
  220.         cout << distVal(A, B) << endl;
  221.     }
  222.    
  223.     return 0;
  224. }
  225.  
  226. #include <bits/stdc++.h>
  227. using namespace std;
  228. const int MX = 1e5;
  229.  
  230. int par[MX + 1], sz[MX + 1];
  231. long long ans[3 * MX], dist[MX + 1];
  232. vector<int> token[MX + 1];
  233. vector<pair<int, long long>> adj[MX + 1];
  234. pair<int, int> query[3 * MX];
  235. tuple<long long, int, int> edge[3 * MX];
  236.  
  237. int find(int a) {
  238.     if (par[a] == a) return a;
  239.     return par[a] = find(par[a]);
  240. }
  241.  
  242. void unite(int a, int b, long long c) {
  243.     a = find(a);
  244.     b = find(b);
  245.     if (a != b) {
  246.         if (sz[a] > sz[b]) {
  247.             swap(a, b);
  248.         }
  249.         par[a] = b;
  250.         sz[b] += sz[a];
  251.         for (auto i : token[a]) {
  252.             if (query[i].first == query[i].second) continue;
  253.             if (query[i].first != a) {
  254.                 swap(query[i].first, query[i].second);
  255.             }
  256.             query[i].first = b;
  257.             if (query[i].second == b) {
  258.                 ans[i] = c;
  259.             } else {
  260.                 token[b].push_back(i);
  261.             }
  262.         }
  263.     }
  264. }
  265.  
  266. int main() {
  267.     ios_base::sync_with_stdio(0);
  268.     cin.tie(0);
  269.     int n, m, k, q;
  270.     cin >> n >> m >> k >> q;
  271.     for (int i = 0; i < m; ++i) {
  272.         int u, v;
  273.         long long w;
  274.         cin >> u >> v >> w;
  275.         edge[i] = make_tuple(w, u, v);
  276.         adj[u].emplace_back(v, w);
  277.         adj[v].emplace_back(u, w);
  278.     }
  279.    
  280.     memset(dist, 0x3F3F3F3F, sizeof dist);
  281.     priority_queue<pair<long long, int>> dijkstra;
  282.     for (int i = 1; i <= k; ++i) {
  283.         dist[i] = 0;
  284.         dijkstra.emplace(0, i);
  285.     }
  286.     while (!dijkstra.empty()) {
  287.         int u;
  288.         long long d;
  289.         tie(d, u) = dijkstra.top();
  290.         dijkstra.pop();
  291.         if (-d > dist[u]) continue;
  292.         for (auto e : adj[u]) {
  293.             if (-d + e.second < dist[e.first]) {
  294.                 dist[e.first] = -d + e.second;
  295.                 dijkstra.emplace(-dist[e.first], e.first);
  296.             }
  297.         }
  298.     }
  299.     for (int i = 0; i < m; ++i) {
  300.         int u, v;
  301.         tie(ignore, u, v) = edge[i];
  302.         get<0>(edge[i]) += dist[u] + dist[v];
  303.     }
  304.     sort(edge, edge + m);
  305.    
  306.     for (int i = 0; i < q; ++i) {
  307.         int a, b;
  308.         cin >> a >> b;
  309.         query[i] = {a, b};
  310.         token[a].push_back(i);
  311.         token[b].push_back(i);
  312.     }
  313.     iota(par + 1, par + 1 + n, 1);
  314.     fill(sz + 1, sz + 1 + n, 1);
  315.     for (int i = 0; i < m; ++i) {
  316.         int u, v;
  317.         long long w;
  318.         tie(w, u, v) = edge[i];
  319.         unite(u, v, w);
  320.     }
  321.     for (int i = 0; i < q; ++i) {
  322.         cout << ans[i] << '\n';
  323.     }
  324. }
  325.  
  326.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement