#include #include #include #include #include using namespace std; class SegmentTree { public: class Node { public: static const int oo = 0x3f3f3f3f; Node(): minValue(oo), maxValue(-oo) {} Node(const int value): minValue(value), maxValue(value) {} void SetMin(const int value) { minValue = value; } int GetMin() const { return minValue; } void SetMax(const int value) { maxValue = value; } int GetMax() const { return maxValue; } static Node Merge(const Node &left, const Node &right) { Node result; result.SetMin(min(left.GetMin(), right.GetMin())); result.SetMax(max(left.GetMax(), right.GetMax())); return result; } private: int minValue, maxValue; }; SegmentTree(const vector &values): size(1), tree(vector()) { for (; size < int(values.size()); size *= 2); tree = vector(2 * size); for (int x = 0; x < int(values.size()); ++x) tree[size + x] = Node(values[x]); for (int x = size - 1; x > 0; --x) tree[x] = Node::Merge(tree[2 * x], tree[2 * x + 1]); } void UpdateMax(int where, const int value) { tree[where += size].SetMax(value); for (where /= 2; where > 0; where /= 2) tree[where] = Node::Merge(tree[2 * where], tree[2 * where + 1]); } void UpdateMin(int where, const int value) { tree[where += size].SetMin(value); for (where /= 2; where > 0; where /= 2) tree[where] = Node::Merge(tree[2 * where], tree[2 * where + 1]); } Node Query(int from, int to) const { from += size; to += size; Node answer; answer.SetMin(Node::oo); answer.SetMax(-Node::oo); while (from <= to) { answer = Node::Merge(answer, Node::Merge(tree[from], tree[to])); from = (from + 1) / 2; to = (to - 1) / 2; } return answer; } private: int size; vector tree; }; int main() { int v, q; cin >> v >> q; vector values = vector(v); vector< multiset > activeEdges = vector< multiset >(v, multiset()); for (int x = 0; x < v; ++x) { values[x] = x; activeEdges[x].insert(x); } vector< pair > edgeHistory; SegmentTree tree = SegmentTree(values); for (; q > 0; --q) { int type; cin >> type; if (type == 1) { int x, y; cin >> x >> y; --x; --y; edgeHistory.push_back(make_pair(x, y)); activeEdges[x].insert(y); activeEdges[y].insert(x); tree.UpdateMin(x, *activeEdges[x].begin()); tree.UpdateMax(x, *activeEdges[x].rbegin()); tree.UpdateMin(y, *activeEdges[y].begin()); tree.UpdateMax(y, *activeEdges[y].rbegin()); } else if (type == 2) { int index; cin >> index; --index; int x = edgeHistory[index].first, y = edgeHistory[index].second; activeEdges[x].erase(activeEdges[x].find(y)); activeEdges[y].erase(activeEdges[y].find(x)); tree.UpdateMin(x, *activeEdges[x].begin()); tree.UpdateMax(x, *activeEdges[x].rbegin()); tree.UpdateMin(y, *activeEdges[y].begin()); tree.UpdateMax(y, *activeEdges[y].rbegin()); } else if (type == 3) { int from, to; cin >> from >> to; --from; --to; SegmentTree::Node answer = tree.Query(from, to); if (answer.GetMin() == from && answer.GetMax() == to) cout << "YES\n"; else cout << "NO\n"; } } return 0; }