BOJ 25320 - SCV 체인

image.png

무조건 CHAIN 을 끼워넣어야 하는 경우는 A A 처럼 있거나 B B 처럼있거나 제일 뒤가 A인 경우이다.

그리디하게 가장 끼워넣을 수 있는 것 중 작은 것을 끼워넣는다.

이 가장 작은것이 없다면 NO 를 출력한다.

마지막에 안쓰이고 남은 숫자들은 안쓰이고 남은 숫자 중 가장 작은 것보다 작은 것이 있는 적당한 곳에 계속 이어붙이면 된다.

void fail() {  
   cout << "NO";  
   exit(0);  
}  
struct seg_tree {  
   int N;  
   vi tree;  
   seg_tree(int N) : N(N) {  
      int size = 1 << int(ceil(log2(N)) + 1);  
      tree.resize(size);  
   }  
  
   void update(int n, int nl, int nr, int i, int v) {  
      if (i > nr || i < nl) return;  
      if (nl == nr) {  
         tree[n] = v;  
         return;  
      }  
      int m = (nl + nr) >> 1;  
      update(n * 2, nl, m, i, v);  
      update(n * 2 + 1, m + 1, nr, i, v);  
      tree[n] = tree[n * 2] + tree[n * 2 + 1];  
   }  
   int query(int n, int nl, int nr, int l, int r) {  
      if (r < nl || l > nr) return 0;  
      if (nl >= l && nr <= r) return tree[n];  
  
      int m = (nl + nr) >> 1;  
      return query(n * 2, nl, m, l, r) + query(n * 2 + 1, m + 1, nr, l, r);  
   }  
   int query(int lower) {  
      if (lower >= N) return -1;  
      int l = lower, r = N - 1, ret = -1;  
  
      while (l <= r) {  
         int m = (l + r) >> 1;  
         if (query(1, 0, N - 1, lower, m) < m - lower + 1) {  
            ret = m;  
            r = m - 1;  
         } else {  
            l = m + 1;  
         }  
      }  
      return ret;  
   }  
};  
  
void solve() {  
   int n, m;  
   cin >> n >> m;  
   vector<array<int, 3>> his;  
   seg_tree seg(2 * n);  
   vi used(n * 2);  
   for (int i = 0; i < m; i++) {  
      string a, b;  
      int k;  
      cin >> a >> b >> k;  
      k--;  
      his.pb({  
                a == "A" ? 1 : 2,  
                b == "BLOCK" ? 1 : 2,  
                k,  
             });  
      seg.update(1, 0, 2 * n - 1, k, 1);  
      used[k] = 1;  
   }  
   vector<vector<array<int, 3>>> ans(m);  
   for (int i = 0; i < m; i++) ans[i].pb(his[i]);  
   for (int i = 0; i < m - 1; i++) {  
      if (his[i][0] == his[i + 1][0]) {  
         int nxt = seg.query(his[i][2] + 1);  
         if (nxt == -1) fail();  
         seg.update(1, 0, 2 * n - 1, nxt, 1);  
         ans[i].pb({3 - his[i][0], 2, nxt});  
         used[nxt] = 1;  
      }  
   }  
   vi remain;  
   for (int i = 0; i < 2 * n; i++) if (!used[i]) remain.pb(i);  
  
   auto print = [&]() {  
      cout << "YES\n";  
      for (int i = 0; i < m; i++) {  
         for (auto &[a, b, c]: ans[i]) {  
            cout << (a == 1 ? 'A' : 'B') << ' ' << (b == 1 ? "BLOCK" : "CHAIN") << ' ' << c + 1 << endl;  
         }  
      }  
   };  
  
   if (!sz(remain)) {  
      print();  
      return;  
   }  
   // 가장 뒤가 A로 끝날 경우, B를 무조건 붙여줘야 함  
   if (ans[m - 1].back()[0] == 1) {  
      if (remain.back() < ans[m - 1].back()[2]) fail();  
  
      int j = ubi(remain, ans[m - 1].back()[2]);  
  
      ans[m - 1].pb({2, 2, remain[j]});  
  
      remain.erase(remain.begin() + j);  
   }  
  
   if (!sz(remain)) {  
      print();  
      return;  
   }  
  
   int mn_value = 1e9, mn_idx = -1;  
   for (int i = 0; i < m; i++) {  
      if (ans[i].back()[2] < mn_value) {  
         mn_idx = i, mn_value = ans[i].back()[2];  
      }  
   }  
  
   // 남은 수들을 붙일 데가 없다면,  
   if (mn_value > remain[0]) fail();  
  
   for (int i: remain) ans[mn_idx].pb({3 - ans[mn_idx].back()[0], 2, i});  
   print();  
}

Tags:

Categories:

Updated:

Comments