Submission #629009

#TimeUsernameProblemLanguageResultExecution timeMemory
629009X_RayFactories (JOI14_factories)C++14
100 / 100
4804 ms195408 KiB
#include <bits/stdc++.h> //#pragma GCC optimize ("O2") //#pragma GCC optimize ("O3") //#pragma GCC optimize ("Ofast") //#pragma GCC optimize ("strict-overflow") //#pragma GCC target("avx,avx2,fma") //#pragma comment(linker, "/STACK:268435456"); #define pb push_back #define mp make_pair using namespace std; #include <ext/pb_ds/assoc_container.hpp> using namespace __gnu_pbds; typedef long long ll; typedef long double ld; const ll inf = 1e16; bool blocked[500001]; int n, children[500001], par[500001], cnt[500001], uniRoot; ll ans = 1e16, dis[500001][19]; vector<pair<int, int>> adj[500001]; gp_hash_table<int, ll> minDis; void DFS(int u, int prv){ children[u] = 1; for(auto& i: adj[u]){ if(blocked[i.first] || i.first == prv) continue; DFS(i.first, u); children[u] += children[i.first]; } } int secDFS(int u, int prv){ bool flag = 1; for(auto& i: adj[u]) if(! blocked[i.first] && children[i.first]*2 > children[u]) flag = 0; if(flag) return u; int anc = -1; for(auto& i: adj[u]){ if(i.first == prv || blocked[i.first]) continue; children[u] -= children[i.first]; children[i.first] += children[u]; if(anc == -1) anc = secDFS(i.first, u); children[i.first] -= children[u]; children[u] += children[i.first]; } return anc; } void distDFS(int u, int prv, ll curDis, int root){ dis[u][cnt[u]++] = curDis; for(auto& i: adj[u]){ if(blocked[i.first] || i.first == prv) continue; distDFS(i.first, u, curDis+i.second, root); } } int decompose(int u){ DFS(u, -1); int root = secDFS(u, -1); distDFS(root, -1, 0, root); blocked[root] = 1; for(auto& i: adj[root]) { if(blocked[i.first]) continue; int nextRoot = decompose(i.first); par[nextRoot] = root; } return root; } void Init(int N, int A[], int B[], int C[]) { n = N; for(int i = 0; i < N-1; i++){ adj[A[i]].pb(mp(B[i], C[i])); adj[B[i]].pb(mp(A[i], C[i])); } uniRoot = decompose(0); par[uniRoot] = -1; } ll Query(int S, int X[], int T, int Y[]){ //The answer is the lowest LCA for a pair {X_i, Y_j} in the Centroid Tree //O(STlogN) Naive //How do we process queries in O((S+T)) or O((S+T)logN)? //Idea: for all S, update the shortest distance for all nodes between the root of the centroid tree and X_i, and for Y_i, move up the centroid tree and update the answer for each node. //The height of the centroid tree is O(logN), so we get O((S+T)logN) //We can use Euler Tour Trick to get distances in O(1) //Alternatively just store the distances ans = inf; minDis.clear(); for(int i = 0; i < S; i++){ int cur = X[i], curcnt = cnt[X[i]]-1; while(cur != -1){ if(minDis.find(cur) == minDis.end()) minDis[cur] = inf; minDis[cur] = min(minDis[cur], dis[X[i]][curcnt--]); cur = par[cur]; } } for(int i = 0; i < T; i++){ int cur = Y[i], curcnt = cnt[Y[i]]-1; while(cur != -1){ if(minDis.find(cur) != minDis.end()) ans = min(ans, minDis[cur]+dis[Y[i]][curcnt]); curcnt--; cur = par[cur]; } } assert(ans != 0); return ans; } /* int main() { cin.sync_with_stdio(NULL); cin.tie(NULL); int A[6] = {0, 1, 2, 2, 4, 1}, B[6] = {1, 2, 3, 4, 5, 6}, C[6] = {4, 4, 5, 6, 5, 3}; Init(7, A, B, C); int X1[2] = {0, 6}, Y1[2] = {3, 4}; cout << Query(2, X1, 2, Y1) << "\n"; int X2[3] = {0, 1, 3}, Y2[2] = {4, 6}; cout << Query(3, X2, 2, Y2) << "\n"; int X3[1] = {2}, Y3[1] = {5}; cout << Query(1, X3, 1, Y3) << "\n"; } */
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...