Advertisement
erek1e

IOI '08 P2 - Islands (316.16 MB)

Jun 27th, 2023
884
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.31 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4.  
  5. using namespace std;
  6.  
  7. const long long INF = 1e18;
  8.  
  9. vector<vector<pair<int, int>>> g;
  10. vector<vector<int>> edgeId;
  11.  
  12. // DFS to find cycle
  13. vector<bool> inPath;
  14. vector<pair<int, int>> path; // node, weight from previous node
  15. bool dfsCycle(int node, int parentEdge = 0) {
  16.     if (inPath[node]) return true;
  17.     inPath[node] = true;
  18.     for (size_t i = 0; i < g[node].size(); ++i) {
  19.         auto [child, w] = g[node][i];
  20.         int e = edgeId[node][i];
  21.         if (e != parentEdge) {
  22.             path.emplace_back(child, w);
  23.             if (dfsCycle(child, e)) return true;
  24.             path.pop_back();
  25.         }
  26.     }
  27.     inPath[node] = false;
  28.     return false;
  29. }
  30.  
  31. // DFS to mark as seen
  32. vector<bool> seen;
  33. void dfsComponent(int node) {
  34.     seen[node] = true;
  35.     for (auto [child, w] : g[node]) {
  36.         if (!seen[child]) dfsComponent(child);
  37.     }
  38. }
  39.  
  40. // DFS to find max path length without moving to any banned nodes (may start at a banned node)
  41. vector<bool> bannedNode; // (on cycle)
  42. pair<long long, long long> findMaxPath(int node, int parent = 0) { // (max path starting here, max path in subtree)
  43.     vector<long long> biggestPathsStartingHere;
  44.     long long maxPathFromNode = 0, maxPathInSubtree = 0;
  45.     for (auto [child, w] : g[node]) {
  46.         if (child == parent || bannedNode[child]) continue;
  47.         auto [a, b] = findMaxPath(child, node);
  48.         a += w;
  49.         maxPathFromNode = max(maxPathFromNode, a);
  50.         maxPathInSubtree = max(maxPathInSubtree, b);
  51.         biggestPathsStartingHere.push_back(a);
  52.         sort(biggestPathsStartingHere.rbegin(), biggestPathsStartingHere.rend());
  53.         if (biggestPathsStartingHere.size() > 2) biggestPathsStartingHere.pop_back();
  54.     }
  55.     long long newPath = 0;
  56.     if (biggestPathsStartingHere.size() == 1) newPath = biggestPathsStartingHere[0];
  57.     else if (!biggestPathsStartingHere.empty()) newPath = biggestPathsStartingHere[0] + biggestPathsStartingHere[1];
  58.     maxPathInSubtree = max(maxPathInSubtree, newPath);
  59.     return {maxPathFromNode, maxPathInSubtree};
  60. }
  61.  
  62. int main() {
  63.     ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  64.     int n; cin >> n;
  65.     g.resize(1+n), edgeId.resize(1+n);
  66.     for (int u = 1; u <= n; ++u) {
  67.         int v, w; cin >> v >> w;
  68.         g[u].emplace_back(v, w);
  69.         g[v].emplace_back(u, w);
  70.         edgeId[u].push_back(u);
  71.         edgeId[v].push_back(u);
  72.     }
  73.  
  74.     // treat components separately
  75.     long long totalW = 0;
  76.     inPath.resize(1+n), seen.resize(1+n), bannedNode.resize(1+n);
  77.     for (int r = 1; r <= n; ++r) {
  78.         if (seen[r]) continue;
  79.        
  80.         // Mark component as seen
  81.         dfsComponent(r);
  82.  
  83.         // Find cycle
  84.         path.clear();
  85.         path.emplace_back(r, 0);
  86.         dfsCycle(r);
  87.         vector<pair<int, int>> cycle;
  88.         int last = path.back().first;
  89.         int cur = (int)path.size()-1;
  90.        
  91.         do {
  92.             cycle.push_back(path[cur--]);
  93.         } while (path[cur].first != last);
  94.         reverse(cycle.begin(), cycle.end());
  95.         int m = cycle.size();
  96.         for (auto [node, w] : cycle) bannedNode[node] = true;
  97.        
  98.         // Find longest path in each direction from the cycle
  99.         long long maxPath = 0;
  100.         vector<long long> pathFrom(m);
  101.         for (int i = 0; i < m; ++i) {
  102.             auto [pathFromI, subtreePath] = findMaxPath(cycle[i].first);
  103.             maxPath = max(maxPath, subtreePath);
  104.             pathFrom[i] = pathFromI;
  105.         }
  106.  
  107.         // Try combining pairs of paths leaving the cycle
  108.         long long S = 0;
  109.         for (int i = 0; i < m; ++i) S += cycle[i].second;
  110.  
  111.         long long mxSum = -INF, mxDif = -INF; // max path + prefix, max path - prefix, over all j considered so far
  112.         long long prefix = 0;
  113.         for (int j = 0; j < m; ++j) {
  114.             long long path = pathFrom[j];
  115.             prefix += cycle[j].second;
  116.  
  117.             // i to j clockwise
  118.             long long a = path + prefix + mxDif;
  119.             // j to i clockwise
  120.             long long b = S + path - prefix + mxSum;
  121.             maxPath = max({maxPath, a, b});
  122.  
  123.             mxSum = max(mxSum, path+prefix);
  124.             mxDif = max(mxDif, path-prefix);
  125.         }
  126.  
  127.         totalW += maxPath;
  128.     }
  129.     cout << totalW << endl;
  130.     return 0;
  131. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement