E - Insert or Erase 解説 by miscalculation53

(C++) std::list を用いて実装する方法

公式解説 の内容は前提とします。また、C++ での実装を主に扱います。


C++ の標準ライブラリには双方向リストの機能を持つ std::list があります。std::list のメソッドのうち特によく使うのは次の \(2\) つです。

  • insert: リスト上の位置をイテレータによって指定し、その位置に要素を挿入する

    ls.insert(イテレータ, 要素)
    
  • erase: リスト上の位置をイテレータによって指定し、その位置の要素を削除する

    ls.erase(イテレータ)
    

本問では、挿入・削除を行う位置が要素の値によって指定されます。そこで、値からイテレータを得ることのできる連想配列(std::map や std::unordered_map 等)を別途用意しておけばよいです。

イテレータについては、次の記事が参考になります。


以上の内容を踏まえた C++ での実装例を下記に示します。(using namespace std; をしている場合は std:: は不要です。)

#include <iostream>
#include <list>
#include <map>

int main()
{
  // 初期状態を入力から生成
  int N;
  std::cin >> N;
  std::list<int> ls;  // 双方向リスト
  std::map<int, std::list<int>::iterator> mp;  // 値からリストのイテレータを得るための map
  for (int i = 0; i < N; i++)
  {
    int a;
    std::cin >> a;
    ls.insert(ls.end(), a);       // リストの末尾に挿入 (push_back と同じこと)
    mp[a] = std::prev(ls.end());  // a を指すイテレータを記録
  }

  // クエリに答える
  int Q;
  std::cin >> Q;
  while (Q--)
  {
    int t;
    std::cin >> t;
    if (t == 1)
    {
      int x, y;
      std::cin >> x >> y;
      auto it = mp[x];              // x を指すイテレータ
      ls.insert(std::next(it), y);  // x の直後に y を挿入
      mp[y] = std::next(it);        // y を指すイテレータを記録
    }
    else
    {
      int x;
      std::cin >> x;
      auto it = mp[x];  // x を指すイテレータ
      mp.erase(x);      // x のイテレータの記録を削除
      ls.erase(it);     // リストから x を削除
    }
  }
  
  // 答えを出力
  for (int val : ls)
    std::cout << val << " ";
  std::cout << std::endl;
}

投稿日時:
最終更新: