Problem: cf1372_f
Difficulty: medium
Categories: search
Time limit: 3000 ms, memory limit: 256 MB

Ray lost his array and needs to find it by asking Omkar. Omkar is willing to disclose that the array has the following qualities:

1. The array has $n$ ($1 \le n \le 2 \cdot 10^5$) elements.
2. Every element in the array $a_i$ is an integer in the range $1 \le a_i \le 10^9.$
3. The array is sorted in nondecreasing order.

Ray is allowed to send Omkar a series of queries. A query consists of two integers, $l$ and $r$ such that $1 \le l \le r \le n$. Omkar will respond with two integers, $x$ and $f$. $x$ is the mode of the subarray from index $l$ to index $r$ inclusive. The mode of an array is defined by the number that appears the most frequently. If there are multiple numbers that appear the most number of times, the smallest such number is considered to be the mode. $f$ is the amount of times that $x$ appears in the queried subarray.

The array has $k$ ($1 \le k \le \min(25000,n)$) distinct elements. However, due to Ray's sins, Omkar will not tell Ray what $k$ is. Ray is allowed to send at most $4k$ queries.

Help Ray find his lost array.

Input

The only line of the input contains a single integer $n$ ($1 \le n \le 2 \cdot 10^5$), which equals to the length of the array that you are trying to find.

Interaction

The interaction starts with reading $n$.

Then you can make one type of query:

* "$? \enspace l \enspace r$" ($1 \le l \le r \le n$) where $l$ and $r$ are the bounds of the subarray that you wish to query.

The answer to each query will be in the form "$x \enspace f$" where $x$ is the mode of the subarray and $f$ is the number of times $x$ appears in the subarray.

* $x$ satisfies ($1 \leq x \leq 10^9$).
* $f$ satisfies ($1 \leq f \leq r-l+1$).
* If you make more than $4k$ queries or violate the number range in the query, you will get an output "-1."
* If you terminate after receiving the response "$-1$", you will get the "Wrong answer" verdict. Otherwise you can get an arbitrary verdict because your solution will continue to read from a closed stream.

To output your answer, print:

* "$! \enspace a_1 \enspace a_2 \enspace \ldots \enspace a_{n-1} \enspace a_n$" which is an exclamation point followed by the array with a space between every element.

And quit after that. This query is not counted towards the $4k$ queries limit.

After printing a query do not forget to output 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 documentation for other languages.

Example

Input

```
6

2 2

2 2

3 2

2 1
```

Output

```
? 1 6

? 1 3

? 4 6

? 3 4

! 1 2 2 3 3 4
```

Note

The first query is $l=1$ and $r=6$. The mode is $2$, and $2$ appears $2$ times, so $x=2$ and $f=2$. Note that $3$ also appears two times, but $2$ is outputted because $2$ is smaller.

The second query is $l=1$ and $r=3$. The mode is $2$ and $2$ appears twice in the subarray with indices $[1,3]$.

The third query is $l=4$ and $r=6$. The mode is $3$ and $3$ appears twice in the subarray with indices $[4,6]$.

The fourth query is $l=3$ and $r=4$. The mode is $2$, which appears once in the subarray with indices $[3,4]$. Note that $3$ also appears once in that range, but $2$ is smaller than $3$.

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;

static void log_metrics() {
    try {
        tout << "queries=" << queries << "\n";
        tout << "query_limit=" << query_limit << "\n";
        tout.flush();
    } catch (...) {
        
    }
}

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

static bool parseLongLong(const string& s, long long& out) {
    if (s.empty()) return false;
    int i = 0;
    bool neg = false;
    if (s[i] == '-') {
        neg = true;
        i++;
        if (i == (int)s.size()) return false;
    }
    long long val = 0;
    for (; i < (int)s.size(); i++) {
        char c = s[i];
        if (c < '0' || c > '9') return false;
        int d = c - '0';
        if (val > (LLONG_MAX - d) / 10) return false;
        val = val * 10 + d;
    }
    out = neg ? -val : val;
    return true;
}

static inline pair<int,int> combineBest(const pair<int,int>& a, const pair<int,int>& b) {
    if (a.first != b.first) return (a.first > b.first) ? a : b;
    return (a.second < b.second) ? a : b; 
}

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

    int n = inf.readInt(1, 200000, "n");
    vector<long long> a(n + 1);
    for (int i = 1; i <= n; i++) {
        a[i] = inf.readLong(1LL, 1000000000LL, ("a[" + to_string(i) + "]").c_str());
        if (i > 1 && a[i] < a[i - 1]) {
            finish(_fail, "Hidden array is not nondecreasing.");
        }
    }

    
    vector<int> gid(n + 1, -1);
    vector<int> L, R, len;
    vector<long long> val;
    L.reserve(n);
    R.reserve(n);
    len.reserve(n);
    val.reserve(n);

    int m = 0;
    for (int i = 1; i <= n; ) {
        int j = i;
        while (j <= n && a[j] == a[i]) j++;
        int l = i, r = j - 1;
        int cnt = r - l + 1;
        val.push_back(a[i]);
        L.push_back(l);
        R.push_back(r);
        len.push_back(cnt);
        for (int t = l; t <= r; t++) gid[t] = m;
        m++;
        i = j;
    }

    query_limit = 4LL * m;
    long long hard_cap = max(200000LL, 10LL * query_limit);

    
    vector<int> lg(m + 1, 0);
    for (int i = 2; i <= m; i++) lg[i] = lg[i / 2] + 1;
    int K = (m == 0) ? 1 : (lg[m] + 1);
    vector<vector<pair<int,int>>> st(K, vector<pair<int,int>>(m));
    for (int i = 0; i < m; i++) st[0][i] = {len[i], i};
    for (int k = 1; k < K; k++) {
        int span = 1 << k;
        int half = span >> 1;
        for (int i = 0; i + span <= m; i++) {
            st[k][i] = combineBest(st[k - 1][i], st[k - 1][i + half]);
        }
    }

    auto rmq = [&](int l, int r) -> pair<int,int> {
        
        int length = r - l + 1;
        int k = lg[length];
        int span = 1 << k;
        return combineBest(st[k][l], st[k][r - span + 1]);
    };

    
    cout << n << "\n";
    cout.flush();

    
    log_metrics();

    while (true) {
        string cmd;
        if (!(cin >> cmd)) {
            finish(_wa, "EOF from contestant before final answer.");
        }

        if (cmd == "?") {
            string sl, sr;
            if (!(cin >> sl >> sr)) {
                cout << "-1\n";
                cout.flush();
                finish(_pe, "Malformed query: expected two integers after '?'.");
            }
            long long lll, rll;
            if (!parseLongLong(sl, lll) || !parseLongLong(sr, rll)) {
                cout << "-1\n";
                cout.flush();
                finish(_pe, "Malformed query: l/r are not valid integers.");
            }

            queries++;
            if (queries > hard_cap) {
                cout << "-1\n";
                cout.flush();
                finish(_pe, "Hard cap exceeded (too many queries).");
            }

            if (lll < 1 || rll < 1 || lll > rll || rll > n) {
                cout << "-1\n";
                cout.flush();
                finish(_wa, "Query out of bounds.");
            }

            int l = (int)lll;
            int r = (int)rll;

            int gl = gid[l];
            int gr = gid[r];
            long long x, f;

            if (gl == gr) {
                x = val[gl];
                f = (long long)(r - l + 1);
            } else {
                long long leftPart = (long long)(R[gl] - l + 1);
                long long rightPart = (long long)(r - L[gr] + 1);

                long long bestFreq = leftPart;
                int bestIdx = gl;

                if (rightPart > bestFreq || (rightPart == bestFreq && gr < bestIdx)) {
                    bestFreq = rightPart;
                    bestIdx = gr;
                }

                if (gl + 1 <= gr - 1) {
                    auto mid = rmq(gl + 1, gr - 1);
                    long long midFreq = mid.first;
                    int midIdx = mid.second;
                    if (midFreq > bestFreq || (midFreq == bestFreq && midIdx < bestIdx)) {
                        bestFreq = midFreq;
                        bestIdx = midIdx;
                    }
                }

                x = val[bestIdx];
                f = bestFreq;
            }

            cout << x << " " << f << "\n";
            cout.flush();
        } else if (cmd == "!") {
            vector<long long> out(n + 1, 0);
            for (int i = 1; i <= n; i++) {
                string s;
                if (!(cin >> s)) {
                    finish(_pe, "Final answer incomplete: not enough numbers.");
                }
                long long v;
                if (!parseLongLong(s, v)) {
                    finish(_pe, "Final answer contains a non-integer token.");
                }
                out[i] = v;
            }
            for (int i = 1; i <= n; i++) {
                if (out[i] != a[i]) {
                    finish(_wa, "Final answer is incorrect.");
                }
            }
            finish(_ok, "OK");
        } else {
            cout << "-1\n";
            cout.flush();
            finish(_pe, "Unknown command token (expected '?' or '!').");
        }
    }
}


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

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

static void log_metrics() {
    try {
        tout << "queries=" << queries << "\n";
        tout << "query_limit=" << query_limit << "\n";
        tout.flush();
    } catch (...) {
        
    }
}

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

struct ModeQueryDS {
    int n = 0;
    vector<long long> a;            
    int K = 0;                      
    vector<long long> val;          
    vector<int> stPos;              
    vector<int> enPos;              
    vector<int> len;                
    vector<int> pos2block;          

    vector<int> lg2;
    vector<vector<pair<int,int>>> st; 

    void build_from_array(int n_, const vector<long long>& arr1indexed) {
        n = n_;
        a = arr1indexed;
        if ((int)a.size() != n + 1) a.assign(n + 1, 0);

        val.clear();
        stPos.clear();
        enPos.clear();
        len.clear();
        pos2block.assign(n + 1, 0);

        if (n == 0) {
            K = 0;
            return;
        }

        int cur = -1;
        for (int i = 1; i <= n; i++) {
            if (i == 1 || a[i] != a[i - 1]) {
                if (cur != -1) {
                    enPos[cur] = i - 1;
                    len[cur] = enPos[cur] - stPos[cur] + 1;
                }
                cur++;
                val.push_back(a[i]);
                stPos.push_back(i);
                enPos.push_back(i);
                len.push_back(1);
            }
            pos2block[i] = cur;
        }
        if (cur >= 0) {
            enPos[cur] = n;
            len[cur] = enPos[cur] - stPos[cur] + 1;
        }
        K = cur + 1;

        build_sparse();
    }

    void build_sparse() {
        if (K <= 0) return;
        lg2.assign(K + 1, 0);
        for (int i = 2; i <= K; i++) lg2[i] = lg2[i / 2] + 1;
        int P = lg2[K] + 1;
        st.assign(P, {});
        st[0].resize(K);
        for (int i = 0; i < K; i++) st[0][i] = {len[i], -i};
        for (int j = 1; j < P; j++) {
            int span = 1 << j;
            int half = span >> 1;
            int lim = K - span + 1;
            st[j].resize(max(0, lim));
            for (int i = 0; i < lim; i++) {
                st[j][i] = max(st[j - 1][i], st[j - 1][i + half]);
            }
        }
    }

    int rmq_best_block(int L, int R) const {
        
        int lenRange = R - L + 1;
        int j = lg2[lenRange];
        int span = 1 << j;
        auto p1 = st[j][L];
        auto p2 = st[j][R - span + 1];
        auto best = max(p1, p2);
        return -best.second; 
    }

    pair<long long, long long> query_mode(int l, int r) const {
        int bL = pos2block[l];
        int bR = pos2block[r];
        if (bL == bR) {
            return {val[bL], (long long)r - l + 1};
        }
        long long leftFreq = (long long)enPos[bL] - l + 1;
        long long rightFreq = (long long)r - stPos[bR] + 1;

        long long internalFreq = 0;
        long long internalVal = (long long)4e18;
        if (bL + 1 <= bR - 1) {
            int idx = rmq_best_block(bL + 1, bR - 1);
            internalFreq = len[idx];
            internalVal = val[idx];
        }

        long long mx = max(leftFreq, max(rightFreq, internalFreq));
        long long x = (long long)4e18;
        if (leftFreq == mx) x = min(x, val[bL]);
        if (rightFreq == mx) x = min(x, val[bR]);
        if (internalFreq == mx) x = min(x, internalVal);
        return {x, mx};
    }
};

static bool readToken(string& s) {
    return (cin >> s) ? true : false;
}

static bool readLL(long long& x) {
    return (cin >> x) ? true : false;
}

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

    int n = inf.readInt(1, 200000, "n");
    vector<long long> rest;
    while (!inf.seekEof()) {
        rest.push_back(inf.readLong());
    }

    bool is_adp = false;
    vector<long long> a1(n + 1, 0);

    if (rest.empty()) {
        
        is_adp = true;
        long long kMax = min(25000, n);
        long long vmin = 1, vmax = 1000000000LL;
        long long range = vmax - vmin + 1;
        long long k = min<long long>(kMax, min<long long>(n, range));
        if (k < 1) k = 1;

        long long base = n / k, rem = n % k;
        long long step = (k == 1) ? 0 : (vmax - vmin) / (k - 1);
        if (k > 1 && step < 1) step = 1;

        int pos = 1;
        for (int i = 0; i < (int)k; i++) {
            long long cnt = base + (i < rem ? 1 : 0);
            long long v = vmin + step * i;
            for (int t = 0; t < cnt; t++) a1[pos++] = v;
        }
        if (pos != n + 1) finish(_pe, "internal: constructed array length mismatch");
    } else if ((int)rest.size() == 3) {
        is_adp = true;
        long long kMax = rest[0];
        long long vmin = rest[1];
        long long vmax = rest[2];
        if (!(1 <= kMax && kMax <= 25000)) finish(_pe, "bad kMax in adaptive input");
        if (!(1 <= vmin && vmin <= 1000000000LL)) finish(_pe, "bad vmin in adaptive input");
        if (!(1 <= vmax && vmax <= 1000000000LL)) finish(_pe, "bad vmax in adaptive input");
        if (vmin > vmax) finish(_pe, "adaptive input: vmin>vmax");

        long long range = vmax - vmin + 1;
        long long k = min<long long>(kMax, min<long long>(n, range));
        if (k < 1) k = 1;

        
        long long base = n / k, rem = n % k;

        long long step = (k == 1) ? 0 : (vmax - vmin) / (k - 1);
        if (k > 1 && step < 1) step = 1;

        int pos = 1;
        for (int i = 0; i < (int)k; i++) {
            long long cnt = base + (i < rem ? 1 : 0);
            long long v = vmin + step * i;
            if (v < vmin || v > vmax) finish(_pe, "internal: value out of bounds in construction");
            for (int t = 0; t < cnt; t++) a1[pos++] = v;
        }
        if (pos != n + 1) finish(_pe, "internal: constructed array length mismatch");
    } else if ((int)rest.size() == n) {
        is_adp = false;
        for (int i = 1; i <= n; i++) {
            long long v = rest[i - 1];
            if (!(1 <= v && v <= 1000000000LL)) finish(_pe, "bad array value in non-adaptive input");
            a1[i] = v;
            if (i > 1 && a1[i] < a1[i - 1]) finish(_pe, "array not nondecreasing in non-adaptive input");
        }
    } else {
        finish(_pe, "bad input schema: expected 3 params (adp) or n values (non)");
    }

    
    ModeQueryDS ds;
    ds.build_from_array(n, a1);
    int kDistinct = ds.K;
    if (kDistinct <= 0) finish(_pe, "internal: K=0");

    query_limit = 4LL * (long long)kDistinct;

    
    log_metrics();

    
    cout << n << '\n';
    cout.flush();

    long long hard_cap = max(200000LL, 10LL * max(1LL, query_limit));

    while (true) {
        string cmd;
        if (!readToken(cmd)) {
            finish(_wa, "contestant terminated without final answer");
        }

        if (cmd == "?") {
            long long lll, rrr;
            if (!readLL(lll) || !readLL(rrr)) finish(_pe, "cannot read l r");
            if (lll < 1 || rrr < 1 || lll > rrr || rrr > n) finish(_pe, "query indices out of range");
            int l = (int)lll, r = (int)rrr;

            queries++;
            if (queries > hard_cap) finish(_pe, "too many queries (hard cap exceeded)");

            auto ans = ds.query_mode(l, r);
            long long x = ans.first;
            long long f = ans.second;
            if (!(1 <= x && x <= 1000000000LL)) finish(_pe, "internal: answered x out of range");
            if (!(1 <= f && f <= (r - l + 1))) finish(_pe, "internal: answered f out of range");

            cout << x << ' ' << f << '\n';
            cout.flush();
        } else if (cmd == "!") {
            vector<long long> out(n + 1, 0);
            for (int i = 1; i <= n; i++) {
                long long v;
                if (!readLL(v)) finish(_wa, "could not read full final array");
                out[i] = v;
            }
            for (int i = 1; i <= n; i++) {
                if (out[i] != a1[i]) {
                    finish(_wa, "final array mismatch");
                }
            }
            finish(_ok, "OK");
        } else {
            finish(_pe, "unknown command token");
        }
    }
}


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

static long long pickGap(long long remaining, int groupsLeft, bool heavyTail) {
    
    long long minNeed = groupsLeft; 
    long long maxHere = remaining - (minNeed - 1);
    if (maxHere <= 1) return 1;
    if (!heavyTail) {
        
        long long up = min<long long>(maxHere, 50);
        return rnd.next(1LL, up);
    } else {
        
        int roll = rnd.next(1, 100);
        if (roll <= 75) {
            long long up = min<long long>(maxHere, 3);
            return rnd.next(1LL, up);
        } else if (roll <= 92) {
            long long up = min<long long>(maxHere, 200);
            return rnd.next(1LL, up);
        } else {
            return rnd.next(1LL, maxHere);
        }
    }
}

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);

    string mode = opt<string>("mode", "non");

    
    
    
    if (mode != "non" && mode != "adp") mode = "non";

    long long seed = 1;
    if (argc >= 2) {
        
        
        seed = atoll(argv[1]);
        if (seed <= 0) seed = 1;
    }

    if (mode == "adp") {
        
        
        
        int n;
        int kMax = opt<int>("kmax", 25000);
        int valueMin = opt<int>("vmin", 1);
        int valueMax = opt<int>("vmax", 1000000000);

        if (seed == 1) {
            n = 1;
            kMax = 1;
        } else if (seed == 2) {
            n = 200000;
            kMax = 25000;
        } else if (seed == 3) {
            n = 200000;
            kMax = 25000;
        } else {
            
            int roll = rnd.next(1, 100);
            if (roll <= 80) n = 200000;
            else n = rnd.next(1, 200000);
            kMax = min(kMax, min(25000, n));
        }

        cout << n << "\n" << kMax << " " << valueMin << " " << valueMax << "\n";
        return 0;
    }

    
    int n = opt<int>("n", 200000);
    n = max(1, min(200000, n));

    vector<long long> a;
    a.reserve(n);

    if (seed == 1) {
        
        n = 1;
        a.push_back(1);
    } else if (seed == 2) {
        
        n = 200000;
        int k = 25000;
        
        long long base = 1000000;
        for (int i = 0; i < k - 1; i++) a.push_back(base + i);
        long long lastVal = base + (k - 1);
        while ((int)a.size() < n) a.push_back(lastVal);
    } else if (seed == 3) {
        
        n = 200000;
        int k = 25000;
        
        vector<int> cnt(k, 8);
        long long total = 0;
        for (int c : cnt) total += c;
        
        int idx = 0;
        while (total < n) {
            cnt[idx % k] += 1;
            total++;
            idx++;
        }
        while (total > n) {
            int j = (idx % k);
            if (cnt[j] > 1) { cnt[j]--; total--; }
            idx++;
        }
        long long base = 500000000;
        for (int i = 0; i < k; i++) {
            for (int t = 0; t < cnt[i]; t++) a.push_back(base + i);
        }
    } else {
        
        
        int rollN = rnd.next(1, 100);
        if (rollN <= 75) n = 200000;
        else n = rnd.next(1, 200000);

        int kCap = min(25000, n);
        int k;
        int rollK = rnd.next(1, 100);
        if (rollK <= 70) k = kCap;                 
        else if (rollK <= 90) k = max(1, kCap - rnd.next(0, min(1000, kCap - 1)));
        else k = rnd.next(1, kCap);

        
        vector<int> cnt(k, 1);
        long long remaining = n;
        for (int i = 0; i < k; i++) {
            int groupsLeft = k - i;
            bool heavyTail = true;
            long long take = pickGap(remaining, groupsLeft, heavyTail);
            cnt[i] = (int)take;
            remaining -= take;
        }
        
        long long sum = 0;
        for (int c : cnt) sum += c;
        if (sum != n) {
            
            cnt.back() += (int)(n - sum);
            if (cnt.back() < 1) cnt.back() = 1;
            
            sum = 0;
            for (int c : cnt) sum += c;
            while (sum > n) {
                for (int i = k - 1; i >= 0 && sum > n; i--) {
                    if (cnt[i] > 1) { cnt[i]--; sum--; }
                }
            }
            while (sum < n) {
                cnt.back()++; sum++;
            }
        }

        
        if (k >= 10 && n >= 50) {
            int pairs = min(k / 5, 3000);
            for (int t = 0; t < pairs; t++) {
                int i = rnd.next(0, k - 2);
                int m = min(cnt[i], cnt[i + 1]);
                if (m > 1) {
                    int target = rnd.next(1, m);
                    
                    int delta1 = cnt[i] - target;
                    int delta2 = cnt[i + 1] - target;
                    if (target >= 1 && cnt.back() + delta1 + delta2 > 0) {
                        cnt[i] = target;
                        cnt[i + 1] = target;
                        cnt.back() += (delta1 + delta2);
                    }
                }
            }
        }

        
        long long s2 = 0;
        for (int &c : cnt) { c = max(1, c); s2 += c; }
        if (s2 != n) {
            cnt.back() += (int)(n - s2);
            if (cnt.back() < 1) cnt.back() = 1;
        }
        
        long long s3 = 0;
        for (int c : cnt) s3 += c;
        while (s3 > n) {
            for (int i = k - 1; i >= 0 && s3 > n; i--) {
                if (cnt[i] > 1) { cnt[i]--; s3--; }
            }
        }
        while (s3 < n) { cnt.back()++; s3++; }

        
        long long v = rnd.next(1LL, 1000000000LL - (long long)k - 5);
        for (int i = 0; i < k; i++) {
            long long step;
            int rs = rnd.next(1, 100);
            if (rs <= 70) step = rnd.next(1LL, 3LL);
            else if (rs <= 95) step = rnd.next(4LL, 1000LL);
            else step = rnd.next(1001LL, 100000LL);
            v += step;
            if (v > 1000000000LL - (k - i - 1)) v = 1000000000LL - (k - i - 1);
            for (int t = 0; t < cnt[i]; t++) a.push_back(v);
        }
        
        if ((int)a.size() > n) a.resize(n);
        while ((int)a.size() < n) a.push_back(a.empty() ? 1 : a.back());
    }

    cout << n << "\n";
    for (int i = 0; i < n; i++) {
        if (i) cout << ' ';
        cout << a[i];
    }
    cout << "\n";
    return 0;
}