BOJ 3045 - 이중 연결 리스트

image.png

완성된 배열 $A$ 를 갖고 있다고 하자.

정답의 개수는 $N - n(LIS_A)$ 이다.

왜냐면 LIS에 포함되지 않은 원소들을 옮김으로써 정렬해줄 수 있기 때문이다.

완성된 배열 $A$는 링크드리스트를 빡구현해서 다시 만들 수 있고,

LIS에 포함되어있지 않은 원소들을 다른 원소 앞이나 뒤에 붙여줄지 결정하는건 std:set 을 잘 활용하면 $O(N \log N)$ 에 가능하다.

struct Node {  
   Node *prev = 0, *next = 0;  
   int num;  
  
   Node(int num) : num(num) {}  
};  
  
void solve() {  
   int N, M;  
   cin >> N >> M;  
   vector<Node *> nodes(N);  
   for (int i = 0; i < N; i++) {  
      nodes[i] = new Node(i);  
      if (i > 0) {  
         nodes[i]->prev = nodes[i - 1];  
         nodes[i - 1]->next = nodes[i];  
      }  
      Node *node = new Node(i);  
   }  
  
   while (M--) {  
      string cmd;  
      int a, b;  
      cin >> cmd >> a >> b, a--, b--;  
      if (a == b) continue;  
      bool is_a_first = nodes[a]->prev == 0;  
      bool is_b_first = nodes[b]->prev == 0;  
      bool is_a_last = nodes[a]->next == 0;  
      bool is_b_last = nodes[b]->next == 0;  
  
      if (cmd == "A") {  
         // 앞에 추가  
         if (nodes[a]->next == nodes[b]) continue;  
  
         if (!is_a_first && !is_a_last) {  
            // a의 양옆 노드 연결  
            nodes[a]->prev->next = nodes[a]->next;  
            nodes[a]->next->prev = nodes[a]->prev;  
         } else if (!is_a_first) {  
            assert(is_a_last);  
            nodes[a]->prev->next = 0;  
         } else if (!is_a_last) {  
            assert(is_a_first);  
            nodes[a]->next->prev = 0;  
         }  
  
         // a를 업데이트  
         nodes[a]->next = nodes[b];  
         nodes[a]->prev = nodes[b]->prev;  
  
         // b의 전 노드를 업데이트  
         if (!is_b_first)  
            nodes[b]->prev->next = nodes[a];  
         // b를 업데이트  
         nodes[b]->prev = nodes[a];  
      } else {  
         // 뒤에 추가  
         if (nodes[a]->prev == nodes[b]) continue;  
  
         if (!is_a_first && !is_a_last) {  
            // a의 양옆 노드 연결  
            nodes[a]->prev->next = nodes[a]->next;  
            nodes[a]->next->prev = nodes[a]->prev;  
         } else if (!is_a_first) {  
            assert(is_a_last);  
            nodes[a]->prev->next = 0;  
         } else if (!is_a_last) {  
            assert(is_a_first);  
            nodes[a]->next->prev = 0;  
         }  
  
         // a를 업데이트  
         nodes[a]->prev = nodes[b];  
         nodes[a]->next = nodes[b]->next;  
  
         // b의 후 노드를 업데이트  
         if (!is_b_last)  
            nodes[b]->next->prev = nodes[a];  
         // b를 업데이트  
         nodes[b]->next = nodes[a];  
      }  
   }  
   int first = -1;  
   for (auto &node: nodes) {  
      if (node->prev == 0) {  
         first = node->num;  
      }  
   }  
   vi result;  
   Node *cur = nodes[first];  
   while (cur) {  
      result.pb(cur->num);  
      cur = cur->next;  
   }  
   for (int i: result) debug(i + 1);  
  
   vi lis(N), m;  
   for (int i = 0; i < N; i++) {  
      int j = lbi(m, result[i]);  
      if (j == sz(m)) m.pb(result[i]);  
      else m[j] = result[i];  
      lis[i] = j + 1;  
   }  
   int cur_lis = maxe(lis);  
   set<int> s;  
   for (int i = N - 1; i >= 0; i--) {  
      if (lis[i] == cur_lis) {  
         s.insert(result[i]);  
         cur_lis--;  
      }  
   }  
   vector<array<int, 3>> ans;  
   for (int i = 0; i < N; i++) {  
      if (hass(s, i)) {  
         continue;  
      }  
      auto it = s.lower_bound(i);  
      if (it == s.end()) {  
         ans.pb({2, i, *s.rbegin()});  
      } else {  
         ans.pb({1, i, *it});  
      }  
      s.insert(i);  
   }  
   cout << sz(ans) << endl;  
   for (auto[a, b, c]: ans) {  
      cout << (a == 2 ? "B " : "A ") << b + 1 << ' ' << c + 1 << endl;  
   }  
  
}

Tags:

Categories:

Updated:

Comments