제출 #393551

#제출 시각아이디문제언어결과실행 시간메모리
393551ADMathNoob새로운 문제 (POI13_ins)C++11
0 / 100
1753 ms36060 KiB
/*
 * author:  ADMathNoob
 * created: 04/22/21 14:39:48
 * problem: https://www.acmicpc.net/problem/8242
 */

/*
g++ boj_8242.cpp -D_DEBUG -std=c++11 -Wl,--stack=268435456 -Wall -Wfatal-errors -ggdb && gdb a
g++ boj_8242.cpp -D_DEBUG -std=c++11 -Wl,--stack=268435456 -O3 -Wall -Wfatal-errors

Try to avoid O(n log^2(n)) per case?

pessimistic
*/

#include <bits/stdc++.h>

using namespace std;

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  int tt;
  cin >> tt;
  while (tt--) {
    int n, m;
    cin >> n >> m;
    vector<int> when(m);
    vector<int> who(m);
    vector<int> others(m);
    for (int j = 0; j < m; j++) {
      cin >> when[j] >> who[j] >> others[j];
      --when[j];
      --who[j];
    }
    int low = 0, high = m;
    while (low < high) {
      int mid = (low + high + 1) >> 1;
      vector<int> cnt(m, -1);
      bool ok = true;
      vector<int> first(n, m);
      vector<int> last(n, -1);
      // check that the claims are consistent for each point in time
      for (int j = 0; j < mid; j++) {
        int t = when[j];
        if (cnt[t] != -1 && cnt[t] != others[j] + 1) {
          ok = false;
        }
        cnt[t] = others[j] + 1;
        first[who[j]] = min(first[who[j]], t);
        last[who[j]] = max(last[who[j]], t);
        // assert(0 <= first[who[j]] && first[who[j]] <= last[who[j]] && last[who[j]] < m);
      }  // OK
      if (!ok) {
        high = mid - 1;
        continue;
      }
      // cerr << "first " << mid << ": at first glance, consistent\n";

      {
        // check that there aren't times with too many people already
        vector<int> a(m + 1, 0);
        for (int i = 0; i < n; i++) {
          if (first[i] != m) {
            a[first[i]] += 1;
            a[last[i] + 1] -= 1;
          }
        }
        for (int t = 0; t < m; t++) {
          if (cnt[t] != -1 && a[t] > cnt[t]) {
            // cerr << "too many people at time " << t << '\n';
            ok = false;
          }
          a[t + 1] += a[t];
        }
        assert(a[m] == 0);
        if (!ok) {
          high = mid - 1;
          continue;
        }
      }  // OK

      vector<int> add(m, 0);
      vector<int> remove(m, 0);
      for (int i = 0; i < n; i++) {
        if (first[i] != m) {
          add[first[i]] += 1;
          remove[last[i]] += 1;
        }
      }
      {
        // extend intervals right
        vector<int> new_remove(m, 0);
        int in = 0;  // in the office
        for (int t = 0; t < m; t++) {
          in += add[t];
          if (cnt[t] != -1) {
            if (in > cnt[t]) {
              int drop = in - cnt[t];
              // cerr << "too many at time " << t << "; removing " << drop << "\n";
              assert(t > 0);
              new_remove[t - 1] = drop;
              in -= drop;
            }
          }
        }
        new_remove[m - 1] = in;
        remove = new_remove;
        assert(accumulate(add.begin(), add.end(), 0) == accumulate(remove.begin(), remove.end(), 0));
      }  // OK
      {
        // extend intervals left
        vector<int> new_add(m, 0);
        int in = 0;
        for (int t = m - 1; t >= 0; t--) {
          in += remove[t];
          if (cnt[t] != -1) {
            if (in > cnt[t]) {
              int drop = in - cnt[t];
              assert(t < m - 1);
              new_add[t + 1] = drop;
              in -= drop;
            }
          }
        }
        new_add[0] = in;
        add = new_add;
        assert(accumulate(add.begin(), add.end(), 0) == accumulate(remove.begin(), remove.end(), 0));
      }  // OK

      {
        // check that there aren't times with too many people again
        vector<int> a(m + 1, 0);
        for (int i = 0; i < n; i++) {
          if (first[i] != m) {
            a[first[i]] += 1;
            a[last[i] + 1] -= 1;
          }
        }
        for (int t = 0; t < m; t++) {
          assert(cnt[t] == -1 || a[t] <= cnt[t]);
          a[t + 1] += a[t];
        }
      }

      // cerr << "add remove\n";
      // for (int i = 0; i < m; i++) {
      //   cerr << add[i] << ' ' << remove[i] << '\n';
      // }
      // cerr << '\n';

      int in = 0;
      // cerr << unused << " people unaccounted for\n";
      int needed = 0;
      for (int t = 0; t < m; t++) {
        in += add[t];
        if (cnt[t] != -1) {
          if (in < cnt[t]) {
            needed += cnt[t] - in;
          }
          in = cnt[t];
        }
        in -= remove[t];
        // assert(in >= 0);
      }
      int extras = count(first.begin(), first.end(), m);
      if (needed > extras) {
        ok = false;
      }
      if (ok) {
        low = mid;
      } else {
        high = mid - 1;
      }
    }
    cout << low << '\n';
  }
  return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...