結果

問題 No.3201 Corporate Synergy
ユーザー HoyHoyCharhang
提出日時 2025-07-11 22:03:41
言語 C++23
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 2 ms / 2,000 ms
コード長 6,836 bytes
コンパイル時間 3,779 ms
コンパイル使用メモリ 301,592 KB
実行使用メモリ 6,272 KB
最終ジャッジ日時 2025-07-11 22:03:57
合計ジャッジ時間 4,556 ms
ジャッジサーバーID
(参考情報)
judge3 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 20
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
#define fi first
#define se second
#define rep(i,s,n) for (int i = (s); i < (n); ++i)
#define rrep(i,n,g) for (int i = (n)-1; i >= (g); --i)
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define len(x) (int)(x).size()
#define dup(x,y) (((x)+(y)-1)/(y))
#define pb push_back
#define eb emplace_back
#define Field(T) vector<vector<T>>
using namespace std;
using ll = long long;
using ull = unsigned long long;
template<typename T> using pq = priority_queue<T,vector<T>,greater<T>>;
using P = pair<int,int>;
template<class T>bool chmax(T&a,T b){if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T&a,T b){if(b<a){a=b;return 1;}return 0;}

class UnionFind {
  public:
  vector <int> par;
  vector <int> siz;
  int cnt;
 
  UnionFind(int sz_): par(sz_), siz(sz_, 1), cnt(sz_) {
    for (int i = 0; i < sz_; ++i) par[i] = i;
  }
 
  void init(int sz_) {
    par.resize(sz_);
    siz.assign(sz_, 1);
    for (int i = 0; i < sz_; ++i) par[i] = i;
  }
 
  int root(int x) {
    while (par[x] != x) {
      x = par[x] = par[par[x]];
    }
    return x;
  }
 
  bool merge(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y) return false;
    if (siz[x] < siz[y]) swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    --cnt;
    return true;
  }
 
  bool issame(int x, int y) {
    return root(x) == root(y);
  }
 
  int size(int x) {
    return siz[root(x)];
  }
 
  int group_siz() {
    return cnt;
  }
};

template <typename T>
struct MaxFlow {
  struct edge {
    int to;
    T cap;
    int rev;
    bool is_rev;
  };

  vector<vector<edge>> G;
  vector<int> dist, iter;

  MaxFlow() = default;
  explicit MaxFlow(int n) : G(n) {}

  void add_edge(int from, int to, T cap = 1) {
    G[from].emplace_back(edge{to, cap, (int)G[to].size(), 0});
    G[to].emplace_back(edge{from, 0, (int)G[from].size()-1, 1});
  }

  void debug() {
    for (int i = 0; i < (int)G.size(); ++i) {
      for (edge &e : G[i]) {
        if (e.is_rev) continue;
        edge &rev_e = G[e.to][e.rev];
        cout << i << " -> " << e.to << " : " << "(" << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
      }
    }
  }

  void bfs(const int &s) {
    dist.assign(G.size(), -1);
    dist[s] = 0;
    queue<int> que;
    que.push(s);
    while(!que.empty()) {
      int v = que.front();
      que.pop();
      for (edge &e : G[v]) {
        if (e.cap == 0 || dist[e.to] >= 0) continue;
        dist[e.to] = dist[v] + 1;
        que.push(e.to);
      }
    }
  }

  T dfs(int v, const int &t, T f) {
    if (v == t) return f;
    T ret = 0;
    for (int& i = iter[v]; i < (int)G[v].size(); ++i) {
      edge& e = G[v][i];
      if (e.cap == 0 || dist[v] >= dist[e.to]) continue;
      T d = dfs(e.to, t, min(f - ret, e.cap));
      if (d == 0) continue;
      e.cap -= d;
      G[e.to][e.rev].cap += d;
      ret += d;
      if (f == ret) break;
    }
    return ret;
  }

  T flow(int s, int t, T f_limit = numeric_limits<T>::max()) {
    T ret = 0;
    queue<int> que;
    while(true) {
      bfs(s);
      if (dist[t] == -1) break;
      iter.assign(G.size(), 0);
      while(ret < f_limit) {
        T f = dfs(s, t, f_limit - ret);
        if (f == 0) break;
        ret += f;
      }
    }
    return ret;
  }

  vector<bool> min_cut(int s) {
    vector<bool> used(G.size(), 0);
    used[s] = 1;
    queue<int> que;
    que.push(s);
    while(!que.empty()) {
      int v = que.front();
      que.pop();
      for (edge &e : G[v]) {
        if (e.cap > 0 && !used[e.to]) {
          used[e.to] = 1;
          que.push(e.to);
        }
      }
    }
    return used;
  }
};

template <class T>
struct BurnySolver {
  using table = array<T, 4>;
  int n;
  T a = T(0);
  vector<T> b, c;
  map<pair<int, int>, table> d;
  vector<int> flip;

  MaxFlow<T> G;

  BurnySolver(int n): n(n), b(n), c(n), flip(n, -1) {
    G = MaxFlow<T>(n+2);
  }

  // f == 1 -> s, f == 0 -> t
  void add_constraint(int i, bool f, T cost) {
    (f ? b[i] : c[i]) += cost;
  }

  // f == 1 -> s, f == 0 -> t
  void add_constraint(int i, bool fx, int j, bool fy, T cost) {
    if (i > j) {
      swap(i, j);
      swap(fx, fy);
    }
    d[{i, j}][2*fx+fy] += cost;
  }

  // bool == 0 -> infeasible, bool == 1 -> solved
  pair<T, bool> solve() {
    UnionFind uf(n*2);
    for (auto& e: d) {
      int i, j;
      tie(i, j) = e.first;
      const auto& t = e.second;
      T s = -t[0] + t[1] + t[2] - t[3];
      if (s < 0) {
        uf.merge(i, j+n);
        uf.merge(i+n, j);
      } else if (s > 0) {
        uf.merge(i, j);
        uf.merge(i+n, j+n);
      }
    }
    
    for (int i = 0; i < n; ++i) {
      if (uf.issame(i, i+n)) {
        return {0, 0};
      }
      if (flip[i] != -1) continue;
      int x = uf.root(i);
      int y = uf.root(i+n);

      if (flip[x%n] != -1) {
        flip[i] = int(x >= n);
      } else if (flip[y%n] != -1) {
        flip[i] = int(y < n);
      } else {
        flip[i] = 0;
        flip[x%n] = int(x >= n);
      }
    }
    
    for(auto &e: d) {
      int i, j;
      tie(i, j) = e.first;
      auto& t = e.second;
      if (flip[i]) {
        swap(t[0], t[2]);
        swap(t[1], t[3]);
      }
      if (flip[j]) {
        swap(t[0], t[1]);
        swap(t[2], t[3]);
      }
      T s = -t[0] + t[1] + t[2] - t[3];
      a += t[0];
      (flip[i] ? c[i] : b[i]) += t[2] - t[0];
      (flip[j] ? c[j] : b[j]) += t[3] - t[2];
      t[1] = s;
      t[0] = t[2] = t[3] = 0;
      assert(s >= 0);
    }
    
    for (int i = 0; i < n; ++i) {
      if (flip[i]) {
        swap(b[i], c[i]);
      }
      if (b[i] >= c[i]) {
        a += c[i];
        b[i] -= c[i];
        c[i] = 0;
      } else {
        a += b[i];
        c[i] -= b[i];
        b[i] = 0;
      }
    }

    for (int i = 0; i < n; ++i) {
      if (b[i] > 0) {
        G.add_edge(i, n+1, b[i]);
      }
      if (c[i] > 0) {
        G.add_edge(n, i, c[i]);
      }
    }

    for (auto& e: d) {
      int i, j;
      tie(i, j) = e.first;
      const auto& t = e.second;

      if (t[2] > 0) {
        G.add_edge(i, j, t[2]);
      }
      if (t[1] > 0) {
        G.add_edge(j, i, t[1]);
      }
    }
    return {a + G.flow(n, n+1), 1};
  }

  vector<bool> restore() {
    vector<bool> ret = G.min_cut(n);
    rep(i,0,n) {
      if (flip[i]) {
        ret[i] = 1 - ret[i];
      }
    }
    return ret;
  }
};

static constexpr ll inf = 1000000000000000;

int main() {
  int n;
  cin >> n;
  BurnySolver<ll> bs(n);
  rep(i,0,n) {
    int p;
    cin >> p;
    bs.add_constraint(i, 1, -p);
  }
  int m;
  cin >> m;
  rep(i,0,m) {
    int u, v;
    cin >> u >> v;
    --u, --v;
    bs.add_constraint(u, 0, v, 1, inf);
  }
  int k;
  cin >> k;
  rep(i,0,k) {
    int a, b, s;
    cin >> a >> b >> s;
    --a, --b;
    bs.add_constraint(a, 1, b, 1, -s);
  }
  cout << -bs.solve().fi << endl;
  return 0;
}
0