Submission #1231015

#TimeUsernameProblemLanguageResultExecution timeMemory
1231015arshjeet통행료 (APIO13_toll)C++20
0 / 100
3 ms5952 KiB
#include <bits/stdc++.h> using namespace std; #define int long long #define pb push_back #define fast() ios_base::sync_with_stdio(false); cin.tie(NULL) const int N = 1e5+5; vector<pair<int,int>> g[N]; // old roads: (to, weight) vector<pair<int,int>> forest[N]; // we’ll force all new roads in here first int ppl[N], parentDSU[N], szDSU[N], level[N]; int up[18][N], maxE[18][N]; // binary‐lifting for max‐edge queries int n, m, k; struct Edge { int u,v,w, idx; }; vector<Edge> oldE, newE; int findDSU(int x){ return parentDSU[x]==x?x:parentDSU[x]=findDSU(parentDSU[x]); } void uniteDSU(int a,int b){ a=findDSU(a); b=findDSU(b); if(a==b) return; if(szDSU[a]<szDSU[b]) swap(a,b); parentDSU[b]=a; szDSU[a]+=szDSU[b]; } // 1) Build the forest forcing all new roads in void build_initial_forest(){ // reset DSU for(int i=1;i<=n;i++){ parentDSU[i]=i; szDSU[i]=1; forest[i].clear(); } // add all new roads with w = -1 so they float to top for(auto &e: newE){ forest[e.u].pb({e.v, -1}); forest[e.v].pb({e.u, -1}); uniteDSU(e.u, e.v); } // then add old roads by increasing weight sort(oldE.begin(), oldE.end(), [](auto &a,auto &b){ return a.w < b.w; }); for(auto &e: oldE){ if(findDSU(e.u)!=findDSU(e.v)){ uniteDSU(e.u,e.v); forest[e.u].pb({e.v,e.w}); forest[e.v].pb({e.u,e.w}); } } } // 2) DFS to compute subtree‐flows on this forest int flow[N]; int dfs_flow(int u,int p){ int sum = ppl[u]; for(auto &ed: forest[u]){ int v = ed.first; if(v==p) continue; sum += dfs_flow(v,u); } // record for new‐edge endpoints flow[u] = sum; return sum; } // 3) Lift preprocessing on the forest (treat it as a tree now) void dfs_lca(int u,int p){ for(auto &ed: forest[u]){ int v = ed.first, w = ed.second; if(v==p) continue; level[v] = level[u] + 1; up[0][v] = u; maxE[0][v] = w; dfs_lca(v,u); } } int query_max_on_path(int a,int b){ if(level[a]<level[b]) swap(a,b); int mx = 0; // lift a up int diff = level[a]-level[b]; for(int i=0;i<18;i++){ if(diff & (1<<i)){ mx = max(mx, maxE[i][a]); a = up[i][a]; } } if(a==b) return mx; for(int i=17;i>=0;i--){ if(up[i][a]!=up[i][b]){ mx = max(mx, maxE[i][a]); mx = max(mx, maxE[i][b]); a = up[i][a]; b = up[i][b]; } } mx = max(mx, maxE[0][a]); mx = max(mx, maxE[0][b]); return mx; } signed main(){ fast(); cin>>n>>m>>k; oldE.reserve(m); newE.reserve(k); for(int i=0;i<m;i++){ int u,v,w; cin>>u>>v>>w; oldE.push_back({u,v,w,-1}); } for(int i=0;i<k;i++){ int u,v; cin>>u>>v; newE.push_back({u,v,0,i}); // we'll fill w later } for(int i=1;i<=n;i++) cin>>ppl[i]; // 1. build forest forcing new roads build_initial_forest(); // 2. compute flows dfs_flow(1,0); // extract each new-road's flow = flow at deeper endpoint vector<pair<int,int>> order; // (flow, idx) for(auto &e: newE){ // pick the endpoint with larger depth in the forest // but we don't yet have depth ⇒ reuse flow on v or u? // Actually, each new road bridges two subtrees; the flow through edge = dfs on one side // So we rerun a small DFS per new edge: // (but k≤20, so OK) // I'll choose v-side: memset(flow,0,sizeof flow); dfs_flow(1,0); // but simpler: record flows on both and pick min: int f1 = 0; // sum in subtree if we cut u-v // temporarily remove edge u-v: // just run a small DFS: function<int(int,int,int)> go = [&](int u,int p,int ban_u){ int s = ppl[u]; for(auto &ed: forest[u]){ int v = ed.first; if((u==e.u && v==e.v) || (u==e.v && v==e.u)) continue; if(v==p) continue; s += go(v,u,ban_u); } return s; }; f1 = go(e.u,0,e.u); int f = min(f1, (int)accumulate(ppl+1,ppl+1+n,0LL)-f1); order.push_back({f, e.idx}); flow[e.idx] = f; } // 3. sort new roads by descending flow sort(order.rbegin(), order.rend()); // prepare for LCA/max queries // reset up/maxE for(int i=0;i<18;i++) for(int v=1;v<=n;v++) up[i][v]=maxE[i][v]=0; level[1]=0; dfs_lca(1,0); for(int i=1;i<18;i++){ for(int v=1;v<=n;v++){ up[i][v] = up[i-1][ up[i-1][v] ]; maxE[i][v] = max(maxE[i-1][v], maxE[i-1][ up[i-1][v] ]); } } // 4. fresh DSU, assign tolls for(int i=1;i<=n;i++){ parentDSU[i]=i; szDSU[i]=1; } int64_t ans = 0; for(auto &pr: order){ int f = pr.first; int idx = pr.second; auto &e = newE[idx]; // find min old-edge on path u-v in current DSU-forest int cap = query_max_on_path(e.u, e.v); ans += f * cap; uniteDSU(e.u, e.v); } cout<<ans<<"\n"; return 0; }
#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...