BOJ 26972 - Barn Tree

image.png

부모에서부터 자식으로 가는 간선이 부모 $\to$ 자식에게 결과적으로 값을 줘야한다면 비용으로 $+c$ 를 갖고, 반대라면 $-c$ 를 갖는다고 하자.

어떤 간선에서 $u \rightarrow v$ 로 줄 수 있다면 $u$ 를 큐에 넣고 BFS를 돌린다.

이제 $h_v$가 늘어났으므로 $v$를 큐에넣고 BFS에 돌린다.

이렇게하면 시간안에 올바른 순서를 얻을 수 있다.

BFS에 진행하며 큐에 들어가는 개수의 상한은 $O(E)$이고 항상 자신이 자식에게 줄 수 있을 때 주는 순서대로 답을 구성할 수 있기 때문이다.

struct edge {
   int to, rev_idx, cost;
};

void solve() {
   int n;
   cin >> n;
   vi h(n), par(n);
   fv(h);
   ll tot = acc(h), solo = tot / n;
   vector<vector<edge>> edges(n);
   for (int i = 0, u, v; i < n - 1; i++) {
      cin >> u >> v, u--, v--;
      edges[u].pb({v, sz(edges[v])});
      edges[v].pb({u, sz(edges[u]) - 1});
   }
   vi sub_sum(n), sub_size(n), edge_cost(n, 0);
   function<void(int, int)> fn = [&](int i, int p) -> void {
      par[i] = p;
      sub_sum[i] += h[i];
      sub_size[i]++;
      for (edge &e: edges[i]) {
         if (e.to ^ p) {
            fn(e.to, i);
            sub_sum[i] += sub_sum[e.to];
            sub_size[i] += sub_size[e.to];
            // p -> child
            int cost = sub_size[e.to] * solo - sub_sum[e.to];
            e.cost = cost;
            edges[e.to][e.rev_idx].cost = -cost;
         }
      }
   };
   fn(0, -1);
   queue<int> q;
   for (int i = 0; i < n; i++) {
      for (edge &e: edges[i]) {
         if (h[i] >= e.cost) {
            q.push(i);
            break;
         }
      }
   }
   vector<array<int, 3>> ans;
   while (sz(q)) {
      int cur = q.front();
      q.pop();
      for (edge &e: edges[cur]) {
         if (e.cost > 0 && e.cost <= h[cur]) {
            h[e.to] += e.cost;
            h[cur] -= e.cost;
            ans.pb({cur + 1, e.to + 1, e.cost});
            e.cost = 0;
            edges[e.to][e.rev_idx].cost = 0;
            q.push(e.to);
         }
      }
   }
   cout << sz(ans) << endl;
   for (auto &[s, e, c]: ans) cout << s << ' ' << e << ' ' << c << endl;
}

Tags:

Categories:

Updated:

Comments