Official

E - Blackout 2 Editorial by en_translator


An operation of “breaking a power line” is equivalent to “removing an edge” in graph theory terms, but it is often more difficult to “remove an edge” than to “add an edge” in general.
Then how can we rephrase the operation of “removing an edge” to “adding an edge?”

This time, viewing the operations “in the reverse order” is effective.
Briefly speaking, consider “connecting a power line” instead of “breaking a power line.”
Rephrase the problem as follows:

Initially, there are \(N\) cities and \(M\) power plants, and some places are connected with power lines.
(Here, the power lines that are never broken in the original problem are considered initially connected.)

Then, \(Q\) events are given. (These events are sorted in the reverse order than the original problem.)
In each event, the following happens:

  • First, count the number of currently electrified cities.
  • Then, connect Place \(U_i\) and Place \(V_i\) with a power line.

If this problem can be solved, then the original problem can be solved as well.
(Weighted) Union-Find is good at solving the problem of determining whether a connected components contain a power plant while adding edges.
You can determine the number of currently electrified cities while adding edges by the following procedures:

  • If Places \(U_i\) and \(V_i\) belong to the same connected component, then ignore these edges.
  • Otherwise, first check if the connected components that Places \(U_i\) and \(V_i\) belongs contain a power plant.
    • If both connected components contain/do not contain a power plant, then no new city is newly electrified.
    • If one of the connected components contain a power plant while the other doesn’t, then the cities contained in the connected component without a power plant is newly electrified. (The number of such cities should be stored by some means. Note that every place in the connected component without a power plant is an unelectrified city, so the number coincides with the size of connected component without a power plant).
  • Finally, merge the two connected components.

Note that, even if you don’t have an implementation of weighted Union-Find, you may still use a function that returns the root (the representative element) equipped in ordinary Union-Find libraries in order to achieve the same purpose to using weighted Union-Find.

Sample Code (C++):

#include<bits/stdc++.h>
#include<atcoder/all>

using namespace std;
using namespace atcoder;

int main(){
  int n,m,e;
  cin >> n >> m >> e;
  vector<int> u(e),v(e);
  for(int i=0;i<e;i++){
    cin >> u[i] >> v[i];
    u[i]--;v[i]--;
  }

  vector<int> fl(e,1);
  int q;
  cin >> q;
  vector<int> query(q);
  for(auto &nx : query){
    cin >> nx;
    nx--;
    fl[nx]=0;
  }

  dsu uf(n+m);
  vector<int> w(n+m,0);
  for(int i=n;i<n+m;i++){w[i]=1;}
  int cur=0;
  for(int i=0;i<e;i++){
    if(fl[i]==0){continue;}
    if(uf.same(u[i],v[i])){continue;}
    int fu=w[uf.leader(u[i])];
    int fv=w[uf.leader(v[i])];
    if(fu==0 && fv==1){cur+=uf.size(u[i]);}
    if(fu==1 && fv==0){cur+=uf.size(v[i]);}
    uf.merge(u[i],v[i]);
    w[uf.leader(u[i])]=max(fu,fv);
  }
  
  vector<int> res;
  for(int j=q-1;j>=0;j--){
    int i=query[j];
    res.push_back(cur);
    if(uf.same(u[i],v[i])){continue;}
    int fu=w[uf.leader(u[i])];
    int fv=w[uf.leader(v[i])];
    if(fu==0 && fv==1){cur+=uf.size(u[i]);}
    if(fu==1 && fv==0){cur+=uf.size(v[i]);}
    uf.merge(u[i],v[i]);
    w[uf.leader(u[i])]=max(fu,fv);
  }
  
  reverse(res.begin(),res.end());
  for(auto &nx : res){cout << nx << "\n";}
  return 0;
}

posted:
last update: