Problem: cf1819_e
Difficulty: medium
Categories: graph
Time limit: 3000 ms, memory limit: 256 MB

This is an interactive problem.

As is well known, the city "E" has never had its roads repaired in its a thousand and a half years old history. And only recently the city administration repaired some of them.

It is known that in total in the city "E" there are $n$ intersections and $m$ roads, which can be used in both directions, numbered with integers from $1$ to $m$. The $i$-th road connects intersections with numbers $a_i$ and $b_i$.

Among all $m$ roads, some subset of the roads has been repaired, but you do not know which one. The only information you could get from the city's road services is that you can get from any intersection to any other intersection by driving only on the roads that have been repaired.

You are a young entrepreneur, and decided to organize a delivery service of fresh raw meat in the city "E" (in this city such meat is called "steaks", it is very popular among the locals). You have already recruited a staff of couriers, but the couriers are willing to travel only on repaired roads. Now you have to find out which roads have already been repaired.

The city administration has given you the city for a period of time, so you can make different queries of one of three types:

1. Block the road with the number $x$. In this case, movement on the road for couriers will be forbidden. Initially all roads are unblocked.
2. Unblock the road with the number $x$. In this case, couriers will be able to move on the road $x$ if it is repaired.
3. Try to deliver the order to the intersection with the number $y$. In this case, one of your couriers will start moving from intersection with number $s$ you don't know and deliver the order to intersection with number $y$ if there is a path on unblocked repaired roads from intersection $s$ to intersection $y$. It is guaranteed that intersection $s$ will be chosen beforehand.

Unfortunately, the city is placed at your complete disposal for a short period of time, so you can make no more than $100 \cdot m$ requests.

Input

Each test consists of multiple test cases. The first line contains a single integer $t$ ($1 \le t \le 1\,000$) — the number of test cases. The description of test cases follows.

The first line contains two integers $n$ and $m$ ($2 \le n \le 2\,000$, $n - 1 \le m \le 2\,000$) —the number of intersections and roads in the city "E".

Each of the following $m$ lines describes one road. The $i$-th of these lines contains two integers $a_i$ and $b_i$ ($1 \le a_i, b_i \le n$) — the ends of the $i$-th road. It is guaranteed that no road connects the city to itself, while it is possible that there are several roads between a pair of different intersections.

It is guaranteed that the sum of $n$ and the sum of $m$ over all test cases does not exceed $2\,000$.

Interaction

Once you have read the description of the test case, you can make queries. Queries can be of three types:

1. "- $x$" ($1 \le x \le m$). In this case the road with the number $x$ is blocked if it has not already been blocked.
2. "+ $x$" ($1 \le x \le m$). In this case the road with the number $x$ is unblocked. Note that road $x$ must be blocked beforehand. All roads are initially unblocked.
3. "? $y$" ($1 \le y \le n$). In this case the jury program chooses some city $s$. If you can get from town $s$ to town $y$ by unblocked repaired roads, the jury program will output $1$, otherwise the jury program will output $0$. Note that city $s$ will be selected before getting information about city $y$, but your previous requests may be taken into account when selecting city $s$.

In total, you can make no more than $100 \cdot m$ queries for each set of input data.

After you have found all repaired roads, output "! $c_1,\ c_2,\ c_3,\ \ldots,\ c_m$", where $c_i$ is $1$ if road $i$ is repaired, and $0$ if road is not repaired. This output will not count in the total number of queries. The jury program will output $1$ if your answer is correct, and $0$ if the answer is not correct. If you received $0$, your program must terminate immediately to receive a Wrong Answer verdict. Otherwise you can get any verdict, because the program will continue reading from the closed stream. If you read $1$, move on to the next test case, or terminate the program if there is none.

Note that you do not have to unblock all roads before outputting the answer. It is guaranteed that all repaired roads are fixed initially and will not be changed by the jury program depending on queries.

After outputting a query or the answer do not forget to output the end of line and flush the output. Otherwise, you will get Idleness limit exceeded. To do this, use:

* fflush(stdout) or cout.flush() in C++;
* System.out.flush() in Java;
* flush(output) in Pascal;
* stdout.flush() in Python;
* see the documentation for other languages.

Example

Input

```
2
2 2
1 2
2 1

1

0

1

1
3 3
1 2
2 3
3 1

1

1

1

0

1

1

1

1
```

Output

```
- 1
? 1

? 2

- 2
+ 1
? 1

! 1 0

- 1
? 2

? 1

- 2
? 3

? 3

+ 1
? 3

? 2

? 1

! 1 1 1
```

Note

In the first test case, road $1$ was repaired, while road $2$ was not. For the first delivery request, intersection $1$ was selected as $s$, and the path from intersection $1$ to $1$ exists. For the second delivery request, intersection $1$ was selected as $s$. Since the only repaired road was blocked, there was no path between intersections $1$ and $2$. For the third delivery request, intersection $2$ was selected as $s$, the path between intersections $2$ and $1$ exists along road $1$, which is repaired and unblocked.

In the second test case, intersections $1$, $3$, $1$, $2$, $2$, $3$, $1$ were selected as starting intersections for delivery requests.

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;


static long long queries = 0;
static long long query_limit = 0;


void log_metrics() {
    
    try {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}


void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

struct Edge {
    int u, v;
};

int main(int argc, char* argv[]) {
    
    registerInteraction(argc, argv);
    
    
    atexit(log_metrics);
    
    
    mt19937 rng(5489u); 

    
    int t = inf.readInt();
    cout << t << endl; 

    
    
    const long long HARD_CAP = 500000; 

    for (int test_case = 1; test_case <= t; ++test_case) {
        
        int n = inf.readInt();
        int m = inf.readInt();
        
        
        query_limit += 100LL * m;
        
        log_metrics();
        
        vector<Edge> edges;
        edges.reserve(m);
        for(int i = 0; i < m; ++i) {
            int u = inf.readInt();
            int v = inf.readInt();
            edges.push_back({u, v});
        }
        
        vector<int> repaired(m);
        for(int i = 0; i < m; ++i) {
            repaired[i] = inf.readInt();
        }
        
        
        cout << n << " " << m << endl;
        for(const auto& e : edges) {
            cout << e.u << " " << e.v << endl;
        }
        cout.flush(); 
        
        
        
        vector<vector<pair<int, int>>> adj(n + 1);
        for(int i = 0; i < m; ++i) {
            adj[edges[i].u].push_back({edges[i].v, i});
            adj[edges[i].v].push_back({edges[i].u, i});
        }
        
        
        vector<bool> blocked(m, false);
        
        
        while (true) {
            if (queries > HARD_CAP) {
                finish(_pe, "Hard query limit exceeded (infinite loop?)");
            }

            string token;
            if (!(cin >> token)) {
                
                finish(_wa, "Unexpected EOF (solution exited early?)");
            }
            
            if (token == "+") {
                int x; 
                if (!(cin >> x)) finish(_pe, "Expected integer after +");
                queries++;
                
                if (x < 1 || x > m) finish(_pe, "Road index out of range");
                blocked[x-1] = false;
                
            } else if (token == "-") {
                int x;
                if (!(cin >> x)) finish(_pe, "Expected integer after -");
                queries++;
                
                if (x < 1 || x > m) finish(_pe, "Road index out of range");
                blocked[x-1] = true;
                
            } else if (token == "?") {
                int y;
                if (!(cin >> y)) finish(_pe, "Expected integer after ?");
                queries++;
                
                if (y < 1 || y > n) finish(_pe, "Intersection index out of range");
                
                
                int s = uniform_int_distribution<int>(1, n)(rng);
                
                
                bool reachable = false;
                if (s == y) {
                    reachable = true;
                } else {
                    queue<int> q;
                    q.push(s);
                    vector<bool> vis(n + 1, false);
                    vis[s] = true;
                    
                    while(!q.empty()) {
                        int u = q.front(); q.pop();
                        if (u == y) {
                            reachable = true;
                            break;
                        }
                        for(auto& edge : adj[u]) {
                            int v = edge.first;
                            int id = edge.second;
                            
                            if (!vis[v] && repaired[id] == 1 && !blocked[id]) {
                                vis[v] = true;
                                q.push(v);
                            }
                        }
                    }
                }
                
                cout << (reachable ? 1 : 0) << endl;
                
            } else if (token == "!") {
                
                vector<int> ans(m);
                bool correct = true;
                for(int i = 0; i < m; ++i) {
                    if (!(cin >> ans[i])) finish(_pe, "Expected m integers in answer");
                    if (ans[i] != repaired[i]) {
                        correct = false;
                    }
                }
                
                if (correct) {
                    cout << 1 << endl; 
                    break; 
                } else {
                    cout << 0 << endl; 
                    finish(_wa, "Incorrect answer mask");
                }
                
            } else {
                finish(_pe, "Invalid query token: " + token);
            }
            
            
            if (queries % 100 == 0) log_metrics();
        }
    }

    finish(_ok, "All cases passed");
    return 0;
}


Adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;















long long global_queries = 0;
long long global_limit = 0;

void log_metrics() {
    try {
        if (tout.is_open()) {
            tout << "queries=" << global_queries << endl;
            tout << "query_limit=" << global_limit << endl;
        }
    } catch (...) {
        
    }
}

void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}


mt19937 rng(1819);

int main(int argc, char** argv) {
    
    registerInteraction(argc, argv);
    atexit(log_metrics);

    
    int t = inf.readInt();
    cout << t << endl; 

    for (int i = 0; i < t; ++i) {
        
        int n = inf.readInt();
        int m = inf.readInt();
        
        
        cout << n << " " << m << endl;

        
        struct Edge { int u, v; };
        vector<Edge> edges;
        vector<vector<int>> adj(n + 1);
        edges.reserve(m);
        
        for(int j = 0; j < m; ++j) {
            int u = inf.readInt();
            int v = inf.readInt();
            edges.push_back({u, v});
            adj[u].push_back(j);
            adj[v].push_back(j);
            
            
            cout << u << " " << v << endl;
        }

        
        vector<int> repaired(m);
        for(int j = 0; j < m; ++j) {
            repaired[j] = inf.readInt();
        }

        
        vector<int> blocked(m, 0);

        
        long long local_limit = 100LL * m;
        global_limit += local_limit;
        long long local_queries = 0;

        
        log_metrics();

        bool case_active = true;
        while(case_active) {
            string type;
            if (!(cin >> type)) {
                finish(_pe, "Unexpected end of file reading query type");
            }

            if (type == "+" || type == "-") {
                int x;
                if (!(cin >> x)) finish(_pe, "Expected road index");
                if (x < 1 || x > m) finish(_pe, "Invalid road index");

                blocked[x-1] = (type == "-"); 
                
                local_queries++;
                global_queries++;
            } 
            else if (type == "?") {
                int y;
                if (!(cin >> y)) finish(_pe, "Expected intersection index");
                if (y < 1 || y > n) finish(_pe, "Invalid intersection index");

                
                int s = std::uniform_int_distribution<int>(1, n)(rng);

                
                
                bool found = false;
                if (s == y) {
                    found = true;
                } else {
                    queue<int> q;
                    q.push(s);
                    vector<bool> vis(n + 1, false);
                    vis[s] = true;

                    while(!q.empty()) {
                        int curr = q.front(); q.pop();
                        if (curr == y) { found = true; break; }
                        
                        for(int e_idx : adj[curr]) {
                            if (repaired[e_idx] && !blocked[e_idx]) {
                                int nxt = (edges[e_idx].u == curr ? edges[e_idx].v : edges[e_idx].u);
                                if (!vis[nxt]) {
                                    vis[nxt] = true;
                                    q.push(nxt);
                                }
                            }
                        }
                    }
                }
                
                cout << (found ? 1 : 0) << endl;
                local_queries++;
                global_queries++;
            } 
            else if (type == "!") {
                vector<int> ans(m);
                bool ok = true;
                for(int j = 0; j < m; ++j) {
                    if (!(cin >> ans[j])) finish(_pe, "Failed to read answer mask");
                    if (ans[j] != repaired[j]) ok = false;
                }
                
                if (ok) {
                    cout << 1 << endl; 
                    case_active = false;
                } else {
                    cout << 0 << endl; 
                    finish(_wa, "Incorrect repaired roads mask");
                }
            } 
            else {
                finish(_pe, "Unknown query type");
            }

            
            if (local_queries > local_limit) {
                finish(_wa, "Query limit exceeded for this test case");
            }
            
            
            if (global_queries > 500000) {
                finish(_pe, "Hard query limit exceeded (infinite loop?)");
            }
            
            
            if (global_queries % 100 == 0) log_metrics();
        }
    }

    finish(_ok, "All cases passed");
    return 0;
}


Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;





















int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);
    
    
    string mode = opt<string>("mode", "non");
    
    
    const int TOTAL_BUDGET = 2000;
    int used_budget = 0;
    
    struct TestCase {
        int n, m;
        vector<pair<int, int>> edges;
        vector<int> repaired; 
    };
    vector<TestCase> cases;
    
    
    
    while (used_budget <= TOTAL_BUDGET - 3) { 
        int rem = TOTAL_BUDGET - used_budget;
        
        
        int n;
        
        if (cases.empty() && rnd.next(3) == 0) {
            
            
            int max_n = (rem + 1) / 2;
            max_n = min(max_n, 2000); 
            if (max_n < 2) max_n = 2;
            n = rnd.next(2, max_n);
        } else {
            
            int max_n = (rem + 1) / 2;
            
            int cap = (mode == "adp" ? 60 : 40); 
            n = rnd.next(2, min(max_n, cap));
        }
        
        
        
        
        
        int min_m = n - 1;
        int max_m = rem - n;
        
        if (max_m < min_m) break; 
        
        int m = rnd.next(min_m, max_m);
        
        used_budget += (n + m);
        
        
        
        
        
        
        
        
        
        int type = 0;
        
        if (mode == "adp") {
            
            int r = rnd.next(100);
            if (r < 60) type = 1;      
            else if (r < 80) type = 2; 
            else type = 0;             
        } else {
            
            int r = rnd.next(100);
            if (r < 70) type = 0;      
            else if (r < 85) type = 1; 
            else type = 2;             
        }
        
        
        vector<int> p(n);
        iota(p.begin(), p.end(), 1);
        shuffle(p.begin(), p.end());
        
        vector<pair<int, int>> edges;
        vector<int> repaired;
        edges.reserve(m);
        repaired.reserve(m);
        
        
        if (type == 1) { 
            for(int i = 0; i < n - 1; ++i) {
                edges.push_back({p[i], p[i+1]});
                repaired.push_back(1);
            }
        } else if (type == 2) { 
            for(int i = 1; i < n; ++i) {
                edges.push_back({p[0], p[i]});
                repaired.push_back(1);
            }
        } else { 
            for(int i = 1; i < n; ++i) {
                
                int parent = rnd.next(0, i - 1);
                edges.push_back({p[i], p[parent]});
                repaired.push_back(1);
            }
        }
        
        
        int extra = m - (n - 1);
        for(int i = 0; i < extra; ++i) {
            int u = rnd.next(1, n);
            int v = rnd.next(1, n);
            while (u == v) {
                v = rnd.next(1, n); 
            }
            edges.push_back({u, v});
            
            
            
            
            if (mode == "adp") {
                
                repaired.push_back(rnd.next(10) == 0 ? 1 : 0);
            } else {
                
                repaired.push_back(rnd.next(2));
            }
        }
        
        
        vector<int> perm(m);
        iota(perm.begin(), perm.end(), 0);
        shuffle(perm.begin(), perm.end());
        
        vector<pair<int, int>> final_edges;
        vector<int> final_repaired;
        final_edges.reserve(m);
        final_repaired.reserve(m);
        
        for(int idx : perm) {
            final_edges.push_back(edges[idx]);
            final_repaired.push_back(repaired[idx]);
        }
        
        cases.push_back({n, m, final_edges, final_repaired});
    }
    
    
    cout << cases.size() << endl;
    for(const auto& c : cases) {
        cout << c.n << " " << c.m << endl;
        for(const auto& e : c.edges) {
            cout << e.first << " " << e.second << endl;
        }
        
        for(int i = 0; i < c.m; ++i) {
            cout << c.repaired[i] << (i == c.m - 1 ? "" : " ");
        }
        cout << endl;
    }
    
    return 0;
}