Advertisement
ec1117

Untitled

Nov 27th, 2020
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.64 KB | None | 0 0
  1. 1027F - Session in BSU
  2. This problem has many approaches (as Hall's theorem, Kuhn algorithm (???) and so on), I will explain one (or two) of them.
  3.  
  4. Let's find the answer using binary search. It is obvious that if we can pass all the exams in k days we can also pass them in k+1 days.
  5.  
  6. For the fixed last day k let's do the following thing: firstly, if there exists some exam with the day of the first opportunity to pass it greater than k, then the answer for the day k is false.
  7.  
  8. Next, while there exist exams having only one possibility to pass them (because of the upper bound of the maximum possible day or constraints imposed by the other exams), we choose this day for this exam and continue (after choosing such day there can appear some new exams with the same property). Now there are no exams having only one day to pass them.
  9.  
  10. Let's take a look on the graph where vertices represent days and edges represent exams (the edge between some vertices u and v (u<v) exists iff there is an exam with the first day to pass it equal to u and the second day to pass it equal to v). Let's remove all the exams for which we identified the answer. Now let's take a look on the connected components of this graph and analyze the problem which we have now. Our problem is to choose exactly one vertex incident to each edge of the connected component such that no vertex is chosen twice (and we have to do this for all the connected components we have).
  11.  
  12. Let cntv be the number of vertices in the current connected component and cnte be the number of edges in the current connected component. The answer for the connected component is true iff cnte≤cntv, for obvious reasons. There is very easy constructive method to see how we can do this. If cnte<cntv then the current connected component is a tree. Let's remove some leaf of this tree and set it as the chosen vertex for the edge incident to this leaf (and remove this edge too). If cnte=cntv then let's remove all leaves as in the algorithm for the tree. For the remaining cycle let's choose any edge and any vertex incident to it, set this vertex as the chosen to this edge and remove them. Now we have a chain. Chain is a tree, so let's apply the algorithm for the tree to this chain.
  13.  
  14. So, if for some connected component c holds cntec>cntvc then the answer for the day k is false. Otherwise the answer is true.
  15.  
  16. Overall complexity O(nlogn) because of numbers compressing or using logarithmic data structures to maintain the graph.
  17.  
  18. Also there is another solution (which can be too slow, I don't know why it works). It is well-known fact that if we will apply Kuhn algorithm to the some bipartite graph in order of increasing indices of vertices of the left part, then the last vertex in the left part of this graph which is in the matching will be minimum possible. Oh, that's what we need! Let the left part of this graph consist of days and the right part consist of exams. The edge between some vertices u from the left part and v from the right part exists iff u is one of two days to pass the exam v. Let's apply Kuhn algorithm to this graph, considering days in increasing order. The first day when matching becomes n (all exams are in the matching) will be the answer. I don't know its complexity, really. Maybe it works too fast because of the special properties of the graph... If someone can explain in which time it works I will very happy!
  19.  
  20.  
  21. int n;
  22. vi m;
  23. vpi v;
  24.  
  25. template<int SZ> struct DSU {
  26.     int par[SZ], sz[SZ], co[SZ];
  27.     vi tmp[SZ];
  28.    
  29.     DSU() {
  30.         F0R(i,SZ) par[i] = i, sz[i] = 1;
  31.     }
  32.    
  33.     int get(int x) { // path compression
  34.         if (par[x] != x) par[x] = get(par[x]);
  35.         return par[x];
  36.     }
  37.    
  38.     bool unite(int x, int y) { // union-by-rank
  39.         x = get(x), y = get(y);
  40.         if (sz[x] < sz[y]) swap(x,y);
  41.         co[x] ++;
  42.         if (x == y) return 0;
  43.         sz[x] += sz[y], co[x] += co[y], par[y] = x;
  44.         return 1;
  45.     }
  46. };
  47.  
  48. int M(int x) {
  49.     return lb(all(m),x)-m.begin();
  50. }
  51.  
  52. DSU<MX> D;
  53.  
  54. int main() {
  55.     ios_base::sync_with_stdio(0); cin.tie(0);
  56.     cin >> n;
  57.     F0R(i,n) {
  58.         int x,y; cin >> x >> y;
  59.         m.pb(x), m.pb(y);
  60.         v.pb({x,y});
  61.     }
  62.     sort(all(m)); m.erase(unique(all(m)),m.end());
  63.     for (auto a: v) D.unite(M(a.f),M(a.s));
  64.     F0R(i,sz(m)) D.tmp[D.get(i)].pb(m[i]);
  65.    
  66.     int cans = 0;
  67.     F0R(i,sz(m)) if (D.get(i) == i) {
  68.         if (D.co[i] > D.sz[i]) {
  69.             cout << -1;
  70.             exit(0);
  71.         }
  72.         sort(all(D.tmp[i]));
  73.         if (D.co[i] == D.sz[i]) {
  74.             cans = max(cans,D.tmp[i].back());
  75.         } else {
  76.             cans = max(cans,D.tmp[i][sz(D.tmp[i])-2]);
  77.         }
  78.     }
  79.     cout << cans;
  80. }
  81.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement