import java.util.*;
import java.io.*;

public class Gen {
	FastScanner in;
	PrintWriter out;

	private int done = 0;
	private int donePreliminary = 0;

	final static Random rng = new Random(191919);
	final int maxN = 100 * 1000;
	final int smallTestT = 1000;
	final int maxNumberOfQueries = 100 * 1000;
	final int mediumTestT = 10 * 1000;

	final int ADD = 0, REMOVE = 1, QUESTION = 2;

	class Item implements Comparable<Item> {
		int num, value;

		public Item(int num, int value) {
			super();
			this.num = num;
			this.value = value;
		}

		@Override
		public int compareTo(Item o) {
			if (value == o.value)
				return num - o.num;
			return value - o.value;
		}
	}

	class Query implements Comparable<Query> {
		int type, value;

		public Query(int type, int value) {
			super();
			this.type = type;
			this.value = value;
		}

		@Override
		public String toString() {
			if (type == ADD)
				return "+ " + value;
			if (type == REMOVE)
				return "- " + value;
			if (type == QUESTION)
				return "? " + value;
			return "";
		}

		@Override
		public int compareTo(Query o) {
			if (value == o.value)
				return type - o.type;
			return value - o.value;
		}
	}

	class Test {
		ArrayList<Query> init;
		ArrayList<Query> queries;

		public Test(ArrayList<Query> init, ArrayList<Query> queries) {
			super();
			this.init = init;
			this.queries = queries;
		}
	}

	Test generateRandomTest(int countQueries, int partAdd, int partRemove,
			int partQuestion, int fromAdd, int toAdd, int fromQuestion,
			int toQuestion) {
		return new Test(new ArrayList<Gen.Query>(), generateRandomTestQuery(
				countQueries, partAdd, partRemove, partQuestion, fromAdd,
				toAdd, fromQuestion, toQuestion));
	}

	Test generateMaxRandomTest(int countQueries, int partAdd, int partRemove,
			int partQuestion, int fromAdd, int toAdd, int fromQuestion,
			int toQuestion) {
		return new Test(maxRandomInit(1), generateRandomTestQuery(countQueries,
				partAdd, partRemove, partQuestion, fromAdd, toAdd,
				fromQuestion, toQuestion));
	}

	ArrayList<Query> generateRandomTestQuery(int countQueries, int partAdd,
			int partRemove, int partQuestion, int fromAdd, int toAdd,
			int fromQuestion, int toQuestion) {
		int sumParts = partAdd + partRemove + partQuestion;
		TreeSet<Item> items = new TreeSet<Gen.Item>();
		ArrayList<Query> test = new ArrayList<Gen.Query>();
		if (partAdd != 0 && partRemove != 0) {
			int count = ((countQueries / 100) / 6) * 6;
			countQueries -= count;
			for (int i = 0; i < count; i++) {
				if (i % 6 < 3) {
					test.add(new Query(ADD, i % 6 + 1));
				} else {
					test.add(new Query(REMOVE, i % 6 - 3 + 1));
				}
			}
		}
		for (int i = 0; i < countQueries; i++) {
			int type = rng.nextInt(sumParts);
			if (type < partAdd) {
				int value = fromAdd + rng.nextInt(toAdd - fromAdd + 1);
				items.add(new Item(i, value));
				test.add(new Query(ADD, value));
			} else if (type < partAdd + partRemove) {
				if (items.size() == 0)
					continue;
				Item valueToFind = new Item(-1, fromAdd
						+ rng.nextInt(toAdd - fromAdd + 1));
				Item candidate = items.ceiling(valueToFind);
				if (candidate == null)
					candidate = items.first();
				items.remove(candidate);
				test.add(new Query(REMOVE, candidate.value));
			} else {
				int value = fromQuestion
						+ rng.nextInt(toQuestion - fromQuestion + 1);
				test.add(new Query(QUESTION, value));
			}
		}
		return test;
	}

	Test longFail() {
		int countQueries = maxNumberOfQueries;
		ArrayList<Query> test = new ArrayList<Gen.Query>();
		int countCheck = 1;
		for (int i = 0; i < countQueries - countCheck; i++) {
			test.add(new Query(ADD, maxN));
		}
		for (int i = 0; i < countCheck; i++) {
			test.add(new Query(QUESTION, maxN - 1));
		}
		return new Test(maxRandomInit(1), test);
	}

	ArrayList<Query> generateMaxTest0() {
		int countQueries = maxNumberOfQueries;
		ArrayList<Query> test = new ArrayList<Gen.Query>();
		int countAdd = 1;
		for (int i = 0; i < countAdd; i++) {
			test.add(new Query(ADD, maxN / 2));
		}
		for (int i = 0; i < countQueries - countAdd; i++) {
			test.add(new Query(QUESTION, maxN));
		}

		return test;
	}

	boolean differFromN2(Test test) {
		print(test);
		// int countQuestions = 0;
		// for (Query q : test.queries) {
		// if (q.type == QUESTION)
		// countQuestions++;
		// }
		// out.close();
		// gonarch_akov.main(new String[0]);
		// in = new FastScanner(new File("gonarch.out"));
		// Long[] answer = new Long[countQuestions];
		// for (int i = 0; i < countQuestions; i++) {
		// answer[i] = in.nextLong();
		// }
		// gonarch_akov_otherN2.main(new String[0]);
		// in = new FastScanner(new File("gonarch.out"));
		// for (int i = 0; i < countQuestions; i++) {
		// long k = in.nextLong();
		// if (k != answer[i]) {
		// System.err.println("expected " + answer[i] + " found " + k);
		// System.err.println("FAIL" + i);
		// return true;
		// }
		// }
		// try {
		// out = new PrintWriter(new File("gonarch.in"));
		// } catch (FileNotFoundException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		return false;
	}

	void print(Test test) {
		String filename = "" + (done + 1);
		if (done < 9) {
			filename = "0" + filename;
		}
		PrintWriter out = null;
		try {
			out = new PrintWriter(new File("..\\tests\\" + filename));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		out.println(test.init.size());
		for (Query q : test.init) {
			out.println(q.type + " " + q.value);
		}
		out.println(test.queries.size());
		for (Query query : test.queries) {
			out.println(query);
		}
		out.close();
		done++;
		System.out.println(done);
	}

	void print2(Test test) {
		out.println(test.init.size());
		for (Query q : test.init) {
			out.println(q.type + " " + q.value);
		}
		out.println(test.queries.size());
		for (Query query : test.queries) {
			out.println(query);
		}
	}

	ArrayList<Query> maxInit() {
		ArrayList<Query> result = new ArrayList<Gen.Query>();
		for (int i = 0; i < maxNumberOfQueries; i++) {
			result.add(new Query((i + 1), maxN));
		}
		return result;
	}

	ArrayList<Query> maxRandomInit(int min) {
		ArrayList<Query> result = new ArrayList<Gen.Query>();
		for (int i = 0; i < maxNumberOfQueries; i++) {
			result.add(new Query((i + 1), min + rng.nextInt(maxN - min + 1)));
		}
		return result;
	}

	Test generateSample() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init.add(new Query(2, 1));

		q.add(new Query(ADD, 3));
		q.add(new Query(ADD, 2));
		q.add(new Query(QUESTION, 5));
		q.add(new Query(REMOVE, 2));
		q.add(new Query(QUESTION, 7));
		q.add(new Query(REMOVE, 2));
		q.add(new Query(QUESTION, 4));

		return new Test(init, q);
	}

	Test generateTest2() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init = maxRandomInit(1);

		q.add(new Query(QUESTION, maxN - 19));
		q.add(new Query(QUESTION, 19));
		q.add(new Query(ADD, 19));
		q.add(new Query(QUESTION, 19));
		q.add(new Query(ADD, 18));
		q.add(new Query(QUESTION, 19));
		q.add(new Query(REMOVE, 18));
		q.add(new Query(REMOVE, 19));
		q.add(new Query(QUESTION, maxN - 19));

		return new Test(init, q);
	}

	Test generateTest3() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init = maxRandomInit(smallTestT + 1);

		int count = smallTestT / 6;

		for (int i = 0; i < maxN; i += maxN / count) {
			q.add(new Query(QUESTION, i + 1));
		}
		for (int i = 0; i < maxN; i += maxN / count) {
			q.add(new Query(REMOVE, rng.nextInt(maxN) + 1));
		}
		for (int i = 0; i < maxN; i += maxN / count) {
			q.add(new Query(QUESTION, i + 1));
		}
		for (int i = 0; i < maxN; i += maxN / count) {
			q.add(new Query(ADD, rng.nextInt(maxN) + 1));
		}
		for (int i = 0; i < maxN; i += maxN / count) {
			q.add(new Query(QUESTION, i + 1));
		}

		return new Test(init, q);
	}

	Test generateTest4() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init = maxInit();

		for (int i = 0; i < smallTestT; i++) {
			int type = rng.nextInt(3);
			q.add(new Query(type, rng.nextInt(maxN) + 1));
		}

		return new Test(init, q);
	}

	Test generateMaxTestForN2() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init = maxRandomInit(smallTestT);

		q.add(new Query(REMOVE, rng.nextInt(maxN) + 1));
		
		for (int i = 0; i < smallTestT - 1; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN) + 1));
		}

		return new Test(init, q);
	}

	Test generateTest6() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init.add(new Query(1, 1));

		q.add(new Query(QUESTION, 1));
		q.add(new Query(REMOVE, 1));
		q.add(new Query(QUESTION, 1));
		for (int i = 1; i <= smallTestT / 10; i++) {
			q.add(new Query(ADD, i));
		}
		for (int i = 0; i < smallTestT / 5; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN) + 1));
		}
		q.add(new Query(ADD, 2));
		q.add(new Query(ADD, 3));
		q.add(new Query(ADD, 5));
		q.add(new Query(ADD, 7));
		q.add(new Query(ADD, 2));
		q.add(new Query(ADD, 7));
		for (int i = 0; i < smallTestT / 5; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN) + 1));
		}
		q.add(new Query(QUESTION, 11));
		q.add(new Query(QUESTION, 8));
		q.add(new Query(QUESTION, 19));
		q.add(new Query(REMOVE, 2));
		q.add(new Query(REMOVE, 2));
		;
		for (int i = 0; i < smallTestT / 5; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN) + 1));
		}
		q.add(new Query(QUESTION, 11));
		q.add(new Query(QUESTION, 8));
		q.add(new Query(QUESTION, 19));

		return new Test(init, q);
	}

	Test generateSmallLongFail() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init = maxInit();

		q.add(new Query(REMOVE, rng.nextInt(maxN) + 1));
		
		for (int i = 0; i < smallTestT - 1; i++) {
			q.add(new Query(QUESTION, maxN - i));
		}

		return new Test(init, q);
	}

	Test generateTest8() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init = maxInit();

		for (int i = 0; i < smallTestT * 8 / 10; i++) {
			q.add(new Query(REMOVE, rng.nextInt(maxN / 1000) + 1));
		}

		for (int i = 0; i < smallTestT / 10; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN / 2) + 1));
		}

		return new Test(init, q);
	}

	Test generateTest9() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init = maxInit();

		for (int i = 0; i < smallTestT * 8 / 10; i++) {
			q.add(new Query(rng.nextInt(2), rng.nextInt(maxN / 1000) + 1));
		}

		for (int i = 0; i < smallTestT / 10; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN / 2) + 1));
		}

		return new Test(init, q);
	}

	Test generateTest10() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();
		init = maxInit();

		for (int i = 0; i < smallTestT * 8 / 10; i++) {
			q.add(new Query(rng.nextInt(2), rng.nextInt(maxN / 10000) + 1));
		}

		for (int i = 0; i < smallTestT / 10; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN / 100) + 1));
		}

		return new Test(init, q);
	}

	Test generateTest15() {
		ArrayList<Query> init = new ArrayList<Gen.Query>();
		ArrayList<Query> q = new ArrayList<Gen.Query>();

		q.add(new Query(ADD, maxN / 10));
		q.add(new Query(ADD, maxN / 10));

		for (int i = 0; i < mediumTestT * 7 / 10; i++) {
			q.add(new Query(ADD, rng.nextInt(maxN) + 1));
		}

		for (int i = 0; i < mediumTestT / 10; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN) + 1));
		}

		q.add(new Query(ADD, maxN / 10));
		q.add(new Query(ADD, maxN / 10));
		q.add(new Query(REMOVE, maxN / 10));
		q.add(new Query(REMOVE, maxN / 10));

		for (int i = 0; i < mediumTestT / 10; i++) {
			q.add(new Query(QUESTION, rng.nextInt(maxN) + 1));
		}

		return new Test(init, q);
	}

	void printPrelim(Test test) {
		String filename = "" + (donePreliminary + 1);
		if (donePreliminary < 9) {
			filename = "0" + filename;
		}
		PrintWriter out = null;
		try {
			out = new PrintWriter(new File("../prelim/" + filename));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		out.println(test.init.size());
		for (Query q : test.init) {
			out.println(q.type + " " + q.value);
		}
		out.println(test.queries.size());
		for (Query query : test.queries) {
			out.println(query);
		}
		out.close();
		donePreliminary++;
		System.out.println(donePreliminary);
	}

	void generateCorrectnessGroup() {
		// CORRECTNESS GROUP : 10 TESTS

		//1
		differFromN2(generateMaxRandomTest(smallTestT, 1, 1, 1, 1, maxN, 1, maxN));
		
		// 2 manyAtStart
		differFromN2(generateTest2());

		// 3 manyAtStart check with period
		differFromN2(generateTest3());

		// 4 many at start and all maxN, check with period
		differFromN2(generateTest4());

		// 5 maxTest for N2
		differFromN2(generateMaxTestForN2());

		// 6
		differFromN2(generateTest6());

		// 7 smallLongFail
		differFromN2(generateSmallLongFail());

		// 8
		differFromN2(generateTest8());

		// 9
		differFromN2(generateTest9());

		// 10 smallValues
		differFromN2(generateTest10());
	}

	void generateGroupMZero() {
		// M = 0 GROUP : 10 TESTS

		// 11 1 / 5 - most time of work with optimize = (count != 0)
		differFromN2(generateRandomTest(mediumTestT, 10, 1, 50, 1, maxN, 1,
				maxN));

		// 12 bad if add works too long
		differFromN2(generateRandomTest(mediumTestT, 100, 1, 5, 1, maxN, 1,
				maxN));

		// 13 bad if remove works too long
		differFromN2(generateRandomTest(mediumTestT, 100, 100, 5, 1, maxN, 1,
				maxN));

		// 14
		differFromN2(generateRandomTest(mediumTestT, 10, 1, 100, 1, maxN / 10,
				maxN / 2, maxN));

		// 15
		differFromN2(generateTest15());

		// 16
		differFromN2(generateRandomTest(mediumTestT, 10, 1, 50, 1, maxN / 100,
				maxN * 9 / 10, maxN));

		// 17
		differFromN2(generateRandomTest(mediumTestT, 1, 1, 1, 1, maxN, 1, maxN));

		// 18
		differFromN2(generateRandomTest(mediumTestT, 10, 1, 50, maxN, maxN, 1,
				maxN));

		// 19
		differFromN2(generateRandomTest(mediumTestT, 10, 1, 100, maxN / 100,
				maxN / 50, maxN / 2, maxN));

		// 20
		differFromN2(generateRandomTest(mediumTestT, 10, 1, 200, 1, maxN, 1,
				maxN));

	}

	void generateTLGroup() {
		// TL GROUP : 20 TESTS

		// 21 - 26
		for (int i = 0; i < 6; i++) {
			differFromN2(generateMaxRandomTest(maxNumberOfQueries, 1, 1, 1000,
					1, maxN / 100, 1, maxN));
		}

		// 27 - 33
		for (int i = 0; i < 7; i++) {
			differFromN2(generateMaxRandomTest(maxNumberOfQueries, 1, 1, 1, 1,
					maxN, 1, maxN));
		}

		// 34 - 35
		for (int i = 0; i < 2; i++) {
			differFromN2(generateMaxRandomTest(maxNumberOfQueries, 10, 10, 1,
					1, maxN / 100, 1, maxN));
		}

		// 36 - 40
		for (int i = 0; i < 5; i++) {
			differFromN2(generateMaxRandomTest(maxNumberOfQueries, 1, 1, 1, 1,
					maxN / 100, 1, maxN));
		}
	}

	void generateNoRemovesGroup() {
		// NO REMOVES AND UNIQUE GROUP : 10 TESTS

		// 41
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 1, 1, 1,
				maxN, 1, maxN));

		// 42
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 2, 1, 1,
				maxN, 1, maxN));

		// 43
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 1, 2, 1,
				maxN, 1, maxN));

		// 44
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 1, 10, 1,
				maxN, 1, maxN));

		// 45
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 1, 100,
				1, maxN, 1, maxN));

		// 46
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 1, 1, 1,
				maxN / 100, 1, maxN));

		// 47
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 3, 1, 1,
				maxN / 100, 1, maxN));

		// 48
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 1, 3, 1,
				maxN / 100, 1, maxN));

		// 49
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 1, 13, 1,
				maxN / 100, 1, maxN));

		// 50
		differFromN2(genearateRandomNoRemovesTest(maxNumberOfQueries, 1, 19, 1,
				maxN / 100, 1, maxN));

	}

	Test genearateRandomNoRemovesTest(int countQueries, int partAdd,
			int partQuestion, int fromAdd, int toAdd, int fromQuestion,
			int toQuestion) {
		TreeSet<Query> free = new TreeSet<Gen.Query>();
		for (int i = 1; i <= maxN; i++) {
			free.add(new Query(ADD, i));
		}
		ArrayList<Query> test = new ArrayList<Gen.Query>();
		int sumParts = partAdd + partQuestion;
		ArrayList<Query> init = noRemovesInit(free);
		for (int i = 0; i < countQueries; i++) {
			int type = rng.nextInt(sumParts);
			if (type < partAdd) {
				if (free.size() == 0)
					continue;
				Query valueToFind = new Query(ADD, fromAdd
						+ rng.nextInt(toAdd - fromAdd + 1));
				Query candidate = free.ceiling(valueToFind);
				if (candidate == null)
					candidate = free.first();
				free.remove(candidate);
				test.add(new Query(ADD, candidate.value));
			} else {
				int value = fromQuestion
						+ rng.nextInt(toQuestion - fromQuestion + 1);
				test.add(new Query(QUESTION, value));
			}
		}
		return new Test(init, test);
	}

	ArrayList<Query> noRemovesInit(TreeSet<Query> init) {
		ArrayList<Query> result = new ArrayList<Gen.Query>();
		for (int i = 1; i <= maxN; i += 2) {
			result.add(new Query(i, 1));
			init.remove(new Query(ADD, i));
		}
		return result;
	}

	public void solve() {
		File testDir = new File("..\\tests");
		if (!testDir.exists()) {
			testDir.mkdir();
		}

		// 0 Sample
		//printPrelim(generateSample());

		generateCorrectnessGroup();

		generateGroupMZero();

		generateTLGroup();

		generateNoRemovesGroup();
	}

	public void run() {
		try {
			out = new PrintWriter(new File("gonarch.in"));

			solve();

			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	class FastScanner {
		BufferedReader br;
		StringTokenizer st;

		FastScanner(File f) {
			try {
				br = new BufferedReader(new FileReader(f));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}

		String next() {
			while (st == null || !st.hasMoreTokens()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

	}

	public static void main(String[] arg) {
		new Gen().run();
	}
}