Problem: icpc2023_moscow_regional_h
Difficulty: medium
Categories: graph, search
Time limit: 2000 ms, memory limit: 1024 MB

This is an interactive problem.

The jury has a hidden tree with $n$ vertices, numbered from 1 to $n$ . The tree has $n - 1$ edges, the $i$ -th edge connects vertices $s _ { i }$ and $f _ { i }$ . You do not know the edges, but you can ask jury questions about the tree.

Each query you make must contain one vertex $v$ and a binary string $b$ of length $n - 1$ . The jury does the following things for the query:

• The tree is considered as a rooted tree with vertex $v$ being the root.   
• Each edge of the tree becomes directed. More specifically, if $b _ { i } = 1$ , then the $i$ -th edge becomes directed from $s _ { i }$ to $f _ { i }$ . Otherwise, it is directed from $f _ { i }$ to $s _ { i }$ .   
• The answer to the query is the number of edges that are directed towards the root. In other words, the answer to the query is the number of tree edges for which the distance between its start to $\boldsymbol { v }$ is larger than the distance between its end and $v$ . Here the distance between two vertices is the number of edges on the simple undirected path between these vertices.

Your task is to guess all $s _ { i }$ and $f _ { i }$ in no more than 10 000 queries.

# Interaction Protocol

The first line contains the only integer $n$ ( $2 \leq n \leq 5 0 0$ ) — the number of vertices in the tree.

After reading $n$ , you can make no more than 10 000 queries of form $^ { 6 6 } ?$ $v$ $b ^ { \prime }$ , where $v$ is the vertex number ( $1 \leq v \leq n ,$ ), and $b$ is a binary string of length $n - 1$ .

For each query, the jury responds with a line containing a single integer, denoting the number of edges that are directed towards $v$ .

When you are ready to tell all $s _ { i }$ and $f _ { i }$ , print “! $ ! s _ { 1 } f _ { 1 } s _ { 2 } f _ { 2 } \ldots s _ { n - 1 } f _ { n - 1 } ? .$ .

You may assume that the tree itself and all $s _ { i }$ and $f _ { i }$ are defined before the start of interaction (i.e. tha the interactor is not adaptive).

# Example

<table><tr><td>standard input</td><td>standard output</td></tr><tr><td>3</td><td>？101</td></tr><tr><td>2</td><td></td></tr><tr><td>2</td><td>？200</td></tr><tr><td></td><td>？311</td></tr><tr><td>1</td><td>！2321</td></tr></table>

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

using namespace std;

static int queries = 0;
static constexpr int QUERY_LIMIT = 10000;

static void log_queries() {
    tout << "queries=" << queries << '\n';
    tout << "query_limit=" << QUERY_LIMIT << '\n';
}

[[noreturn]] static void quit_with(TResult verdict, const string& msg) {
    log_queries();
    quitf(verdict, "%s", msg.c_str());
}

int main(int argc, char* argv[]) {
    registerInteraction(argc, argv);
    atexit(log_queries);

    const int n = inf.readInt(2, 500, "n");
    vector<int> s(n), f(n);  
    vector<vector<int>> g(n + 1);
    for (int i = 1; i <= n - 1; i++) {
        s[i] = inf.readInt(1, n, "s");
        inf.readSpace();
        f[i] = inf.readInt(1, n, "f");
        inf.readEoln();
        g[s[i]].push_back(f[i]);
        g[f[i]].push_back(s[i]);
    }

    vector<vector<int>> dist(n + 1, vector<int>(n + 1, -1));
    for (int root = 1; root <= n; root++) {
        queue<int> q;
        dist[root][root] = 0;
        q.push(root);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int v : g[u]) {
                if (dist[root][v] != -1) {
                    continue;
                }
                dist[root][v] = dist[root][u] + 1;
                q.push(v);
            }
        }
    }

    cout << n << endl;

    while (true) {
        string cmd;
        if (!(cin >> cmd)) {
            quit_with(_pe, "Unexpected EOF");
        }

        if (cmd == "?") {
            int v = 0;
            string b;
            if (!(cin >> v >> b)) {
                quit_with(_pe, "Invalid query");
            }
            if (v < 1 || v > n) {
                quit_with(_pe, "Query root out of range");
            }
            if ((int)b.size() != n - 1) {
                quit_with(_pe, "Bad query string length");
            }
            for (char ch : b) {
                if (ch != '0' && ch != '1') {
                    quit_with(_pe, "Bad query string");
                }
            }

            queries++;
            if (queries > QUERY_LIMIT) {
                quit_with(_wa, "Too many queries");
            }

            int toward = 0;
            for (int i = 1; i <= n - 1; i++) {
                const bool dir = (b[i - 1] == '1');
                const int start = dir ? s[i] : f[i];
                const int end = dir ? f[i] : s[i];
                if (dist[v][start] > dist[v][end]) {
                    toward++;
                }
            }

            cout << toward << endl;
            continue;
        }

        if (cmd == "!") {
            vector<int> gs(n), gf(n);
            for (int i = 1; i <= n - 1; i++) {
                if (!(cin >> gs[i] >> gf[i])) {
                    quit_with(_pe, "Invalid answer");
                }
                if (gs[i] < 1 || gs[i] > n || gf[i] < 1 || gf[i] > n) {
                    quit_with(_pe, "Answer out of range");
                }
            }
            for (int i = 1; i <= n - 1; i++) {
                if (gs[i] != s[i] || gf[i] != f[i]) {
                    quit_with(_wa, "Wrong answer");
                }
            }
            quit_with(_ok, "Correct");
        }

        quit_with(_pe, "Unknown command: " + cmd);
    }
}


Adaptive interactor (C++):

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");
    
    
    long long seed_val = 0;
    try {
        seed_val = stoll(argv[1]);
    } catch (...) {
        seed_val = 100; 
    }

    int n;
    int type = -1; 

    
    if (seed_val == 1) {
        n = 2;
        type = 0;
    } else if (seed_val == 2) {
        n = 3;
        type = 1; 
    } else if (seed_val == 3) {
        n = 3;
        type = 2; 
    } else {
        
        int p = rnd.next(1, 100);
        if (p <= 5) n = rnd.next(2, 20);
        else if (p <= 20) n = rnd.next(21, 100);
        else n = rnd.next(450, 500);

        type = rnd.next(0, 5);
    }

    
    int n_override = opt<int>("n", 0);
    if (n_override > 0) {
        n = n_override;
    }

    
    if (mode == "adp") {
        cout << n << endl;
        return 0;
    }

    
    vector<pair<int,int>> edges;
    auto add_edge = [&](int u, int v) {
        edges.push_back({u, v});
    };

    if (type == 0) { 
        
        for (int i = 2; i <= n; ++i)
            add_edge(rnd.next(1, i - 1), i);
    } else if (type == 1) { 
        
        for (int i = 1; i < n; ++i)
            add_edge(i, i + 1);
    } else if (type == 2) { 
        
        for (int i = 2; i <= n; ++i)
            add_edge(1, i);
    } else if (type == 3) { 
        
        int spine = rnd.next(2, n);
        for (int i = 1; i < spine; ++i)
            add_edge(i, i + 1);
        for (int i = spine + 1; i <= n; ++i)
            add_edge(rnd.next(1, spine), i);
    } else if (type == 4) { 
        
        for (int i = 2; i <= n; ++i)
            add_edge(i / 2, i);
    } else { 
        
        int h = rnd.next(2, max(2, n - 2));
        for (int i = 1; i < h; ++i)
            add_edge(i, i + 1);
        for (int i = h + 1; i <= n; ++i)
            add_edge(h, i);
    }

    
    vector<int> p(n + 1);
    iota(p.begin(), p.end(), 0);
    shuffle(p.begin() + 1, p.end());

    vector<pair<int,int>> final_edges;
    for (auto& e : edges) {
        int u = p[e.first];
        int v = p[e.second];
        
        if (rnd.next(2)) swap(u, v);
        final_edges.push_back({u, v});
    }

    
    shuffle(final_edges.begin(), final_edges.end());

    
    cout << n << endl;
    for (const auto& e : final_edges) {
        cout << e.first << " " << e.second << endl;
    }

    return 0;
}