Advertisement
coloriot

HA_58

Jun 29th, 2025
285
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.39 KB | None | 0 0
  1. /*
  2.  
  3. Доказательство условия про два ребра:
  4.  
  5. - inB[v] + inC[v] считаем только по "живым" годам.
  6.  
  7. - Замечание: когда алгоритм закончился, для любой вершины
  8. inB[v] == 1 и inC[v] == 1.
  9.  
  10. - Действительно, исходящих рёбер каждого цвета ровно |V|,
  11. а условие задачи требует ≥1 входа каждого цвета;
  12.  
  13. - поэтому два входа одного цвета в одну вершину невозможны.
  14. */
  15.  
  16.  
  17. /*************************************************************
  18.  *  Для каждого года i есть два ориентированных ребра
  19.  *      Ai ──(blue)──► Bi
  20.  *      Ai ──(red) ─► Ci
  21.  *
  22.  *  Оставляем подмножество лет  S.  Требование условия:
  23.  *
  24.  *  в каждую вершину входит ≥ 1 blue-и ≥ 1 red-ребро.
  25.  *  Поэтому в корректном ответе в вершину не может
  26.  *  входить два ребра одного цвета – иначе какой-то
  27.  *  вершине не хватило бы входов (принцип Дирихле).
  28.  *
  29.  *  Алгоритм “листопад”.
  30.  *  ------------------------------------
  31.  *  • inB[v], inC[v] –- число blue/red входов из ещё
  32.  *    «живых» лет;
  33.  *  • occCnt[v] – число «живых» лет,
  34.  *    где v встречается в A,B или C.
  35.  *  • Очередь Q из вершин, у которых  inB==0 || inC==0.
  36.  *  • Пока Q не пуста:
  37.  *        v = pop()
  38.  *        если  occCnt[v] == 0     continue
  39.  *        для каждого года idx, где v встречается
  40.  *            if removed[idx]      continue
  41.  *            removed[idx] = true
  42.  *            --occCnt[ Aidx ], occCnt[ Bidx ], occCnt[ Cidx ]
  43.  *            --inB[ Bidx ],  --inC[ Cidx ];
  44.  *            если какая-то вершина осталась без входа
  45.  *            ⇒ push в очередь
  46.  *  ответ = удаленные года.
  47.  *  Работает O(N) памяти/времени:
  48.  *  каждый год и вершина обрабатываются максимум один раз.
  49.  *************************************************************/
  50.  
  51. #include <bits/stdc++.h>
  52. using namespace std;
  53.  
  54. struct Triple { int a, b, c; };
  55.  
  56. int main() {
  57.     ios::sync_with_stdio(false);
  58.     cin.tie(nullptr);
  59.  
  60.     int N;
  61.     if (!(cin >> N)) return 0;
  62.  
  63.     vector<Triple> yr(N);
  64.     for (int i = 0; i < N; ++i) cin >> yr[i].a;
  65.     for (int i = 0; i < N; ++i) cin >> yr[i].b;
  66.     for (int i = 0; i < N; ++i) cin >> yr[i].c;
  67.  
  68.     const int SZ = N + 1;                 // вершины 1..N
  69.     vector<int> inB(SZ, 0), inC(SZ, 0), occCnt(SZ, 0);
  70.     vector<vector<int>> occ(SZ);          // годы, где встречается вершина
  71.  
  72.     // собираем "статистику"
  73.     for (int i = 0; i < N; ++i) {
  74.         auto [a,b,c] = yr[i];
  75.         ++inB[b]; ++inC[c];
  76.         for (int v : {a,b,c}) {
  77.             ++occCnt[v];
  78.             occ[v].push_back(i);
  79.         }
  80.     }
  81.  
  82.     queue<int> Q;
  83.     vector<char> inQ(SZ, 0);
  84.     auto push_if_bad = [&](int v) {
  85.         if (occCnt[v] && (inB[v]==0 || inC[v]==0) && !inQ[v]) {
  86.             Q.push(v); inQ[v] = 1;
  87.         }
  88.     };
  89.     for (int v = 1; v <= N; ++v) push_if_bad(v);
  90.  
  91.     vector<char> removedYr(N, 0);
  92.     int removedCnt = 0;
  93.  
  94.     while (!Q.empty()) {
  95.         int v = Q.front(); Q.pop(); inQ[v] = 0;
  96.         if (occCnt[v]==0) continue;          
  97.         // могла обнулиться раньше
  98.  
  99.         for (int idx : occ[v]) {
  100.             if (removedYr[idx]) continue;
  101.             removedYr[idx] = 1;
  102.             ++removedCnt;
  103.  
  104.             auto [a,b,c] = yr[idx];
  105.  
  106.             // убрали год – вершины в нём проявляются на год меньше */
  107.             for (int u : {a,b,c}) {
  108.                 if (--occCnt[u]==0) inQ[u]=0;  
  109.                 // совсем исчезла
  110.             }
  111.  
  112.             // у целей ушёл вход
  113.             if (--inB[b]==0) push_if_bad(b);
  114.             if (--inC[c]==0) push_if_bad(c);
  115.         }
  116.     }
  117.  
  118.     cout << removedCnt << '\n';
  119.     return 0;
  120. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement