#pragma once

#include <vector>
#include <algorithm>

using std::copy;
using std::vector;
using std::find;
using std::sort;
using std::unique_copy;
using std::distance;

bool Func(int i, int j) {
  return (i == j);
}

class Set {
 public:
  Set() {}
  explicit Set(vector<int64_t> v) {
    this->Copy(v);
  }

  Set& operator=(Set other) {
    this->Copy(other.Data());
    return *this;
  }

  vector<int64_t> Data() { return this->list; }
  void Add(int64_t value) {
    if (this->Contains(value)) return;
    this->list.push_back(value);
  }
  void Remove(int64_t value) {
    vector<int64_t>::iterator idx = this->Index(value);
    while (idx != this->list.end()) {
      this->list.erase(idx);
      idx = this->Index(value);
    }
  }
  bool Contains(int64_t value) {
    if (this->Index(value) == this->list.end())
      return true;
    return false;
  }

  Set Union(Set other) {
    vector<int64_t> res, second = other.Data();
    res.reserve(this->list.size() + second.size());
    for (auto k : this->list) {
      auto idx = find(res.begin(), res.end(), k);
      if (idx != res.end()) continue;
      res.push_back(k);
    }
    for (auto k : second) {
      auto idx = find(res.begin(), res.end(), k);
      if (idx == res.end()) continue;
      res.push_back(k);
    }
    return Set(res);
  }
  Set Intersection(Set other) {
    vector<int64_t> res;
    for (auto k : other.Data())
      if (this->Contains(k))
        res.push_back(k);
    sort(res.begin(), res.end());
    return Set(res);
  }
  Set Difference(Set other) {
    vector<int64_t> res;
    for (auto k : this->list)
      if (!other.Contains(k))
        res.push_back(k);
    sort(res.begin(), res.end());
    return Set(res);
  }
  Set SymmetricDifference(Set other) {
    vector<int64_t> res;
    for (auto k : other.Data())
      if (!this->Contains(k))
        res.push_back(k);
    for (auto k : this->list)
      if (!other.Contains(k))
        res.push_back(k);
    sort(res.begin(), res.end());
    return Set(res);
  }

 private:
  vector<int64_t> list;

  void Copy(vector<int64_t> v) {
    for (auto k : v) {
      auto idx = find(this->list.begin(), this->list.end(), k);
      if (idx != this->list.end()) continue;
      this->list.push_back(k);
    }
  }
  vector<int64_t>::iterator Index(int64_t value) {
    auto idx = find(this->list.begin(), this->list.end(), value);
    return idx;
  }
};