atcoder abc221 D - Online games

問題

D - Online games

解法

経路圧縮 + imos法

ログイン日を+1, ログアウト日を-1 してimos法*1で集計する。 取りうる日付が 109 x 2 あるので、座標圧縮を行う必要がある。

#include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<(int)(n);i++)
using ll = long long;

int n;
vector<int> a(200005),b(200005);

// 座標圧縮 + imos法
void solve() {
  map<int,ll> mp; // [何日目, 人数]

  REP(i,n) {
    mp[ a[i] ]++; // ログインを+1
    mp[ a[i]+b[i] ]--; // ログアウトを-1
  }

  int prev_day = 0;
  for(auto [day, count]: mp) {
    mp[day] = count + mp[prev_day];
    prev_day = day;
  }

  vector<int> ans(n+1);
  prev_day = 0;
  // ちょうどi人がログインしていた日数を集計する
  for(auto [day, _]: mp) {
    ans[mp[prev_day]] += day - prev_day;
    prev_day = day;
  }

  REP(i,n) cout << ans[i+1] << " ";
  cout << endl;
  return;
}

int main() {
  cin >> n;
  REP(i,n) cin >> a[i] >> b[i];

  solve();
  return 0;
}

解法2: イベントソート

解説解。座標圧縮より全然楽だった。 Editorial - AtCoder Beginner Contest 221

void solve2() {
  vector<pair<int,int>> x;
  REP(i,n) {
    x.push_back({ a[i], 1 });
    x.push_back({ a[i]+b[i], -1 });
  }

  sort(x.begin(), x.end());

  int cnt = 0;
  vector<int> ans(x.size());
  REP(i, (int)x.size()-1) {
    cnt += x[i].second;
    ans[cnt] += ((x[i + 1].first) - (x[i].first));
  }

  REP(i,n) cout << ans[i+1] << " ";
  cout << endl;
  return;
}

雑感

abc221はA-Dの4完だった。相変わらずE問題の壁が高い。 あとC問題*2が灰diffってまじ?結構難しいと思ったんだけどなあ