Problem: cf1486_c1
Difficulty: easy
Categories: search
Time limit: 1000 ms, memory limit: 256 MB

The only difference between the easy and the hard version is the limit to the number of queries.

This is an interactive problem.

There is an array $a$ of $n$ different numbers. In one query you can ask the position of the second maximum element in a subsegment $a[l..r]$. Find the position of the maximum element in the array in no more than 40 queries.

A subsegment $a[l..r]$ is all the elements $a_l, a_{l + 1}, ..., a_r$. After asking this subsegment you will be given the position of the second maximum from this subsegment in the whole array.

Input

The first line contains a single integer $n$ $(2 \leq n \leq 10^5)$ — the number of elements in the array.

Interaction

You can ask queries by printing "? $l$ $r$" $(1 \leq l < r \leq n)$. The answer is the index of the second maximum of all elements $a_l, a_{l + 1}, \ldots, a_r$. Array $a$ is fixed beforehand and can't be changed in time of interaction.

You can output the answer by printing "! $p$", where $p$ is the index of the maximum element in the array.

You can ask no more than 40 queries. Printing the answer doesn't count as a query.

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

```
5

3

4
```

Output

```
? 1 5

? 4 5

! 1
```

Note

In the sample suppose $a$ is $[5, 1, 4, 2, 3]$. So after asking the $[1..5]$ subsegment $4$ is second to max value, and it's position is $3$. After asking the $[4..5]$ subsegment $2$ is second to max value and it's position in the whole array is $4$.

Note that there are other arrays $a$ that would produce the same interaction, and the answer for them might be different. Example output is given in purpose of understanding the interaction.

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());
}

struct Node {
    long long v1; int i1;
    long long v2; int i2;
};

static const long long NEG_INF = (long long)-4e18;

static Node emptyNode() {
    return Node{NEG_INF, -1, NEG_INF, -1};
}

static Node combineNode(const Node& A, const Node& B) {
    array<pair<long long,int>, 4> cands = {{
        {A.v1, A.i1}, {A.v2, A.i2}, {B.v1, B.i1}, {B.v2, B.i2}
    }};
    vector<pair<long long,int>> v;
    v.reserve(4);
    for (auto &p : cands) if (p.second != -1) v.push_back(p);
    if (v.empty()) return emptyNode();
    sort(v.begin(), v.end(), [](const auto& x, const auto& y){
        if (x.first != y.first) return x.first > y.first;
        return x.second < y.second;
    });
    Node res = emptyNode();
    res.v1 = v[0].first; res.i1 = v[0].second;
    if ((int)v.size() >= 2) {
        res.v2 = v[1].first; res.i2 = v[1].second;
    }
    return res;
}

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

    int n = inf.readInt(2, 100000, "n");

    vector<long long> a(n + 1, 0);
    unordered_set<long long> seen;
    seen.reserve((size_t)n * 2);

    int posMax = 1;
    for (int i = 1; i <= n; ++i) {
        long long x = inf.readLong((long long)-1000000000000000000LL, (long long)1000000000000000000LL, "a[i]");
        if (seen.find(x) != seen.end()) {
            finish(_fail, "invalid hidden input: duplicate array values");
        }
        seen.insert(x);
        a[i] = x;
        if (a[i] > a[posMax]) posMax = i;
    }

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

    
    log_metrics();

    
    cout << n << endl;

    
    int sz = 1;
    while (sz < n) sz <<= 1;
    vector<Node> seg(2 * sz, emptyNode());
    for (int i = 1; i <= n; ++i) {
        seg[sz + (i - 1)] = Node{a[i], i, NEG_INF, -1};
    }
    for (int i = sz - 1; i >= 1; --i) {
        seg[i] = combineNode(seg[2 * i], seg[2 * i + 1]);
    }

    auto rangeQuery = [&](int l, int r) -> Node {
        Node left = emptyNode(), right = emptyNode();
        int L = sz + (l - 1);
        int R = sz + (r - 1);
        while (L <= R) {
            if (L & 1) left = combineNode(left, seg[L++]);
            if (!(R & 1)) right = combineNode(seg[R--], right);
            L >>= 1; R >>= 1;
        }
        return combineNode(left, right);
    };

    while (true) {
        string cmd;
        if (!(cin >> cmd)) {
            finish(_pe, "unexpected EOF from contestant (no final answer)");
        }

        if (!cmd.empty() && cmd[0] == '?') {
            long long lll, rrr;
            if (!(cin >> lll >> rrr)) {
                finish(_pe, "malformed query: expected two integers after '?'");
            }
            if (lll < 1 || rrr < 1 || lll > n || rrr > n) {
                finish(_pe, "query indices out of range");
            }
            int l = (int)lll, r = (int)rrr;
            if (l >= r) {
                finish(_pe, "malformed query: require l < r");
            }

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

            Node ans = rangeQuery(l, r);
            if (ans.i2 == -1) {
                finish(_fail, "internal error: second maximum missing for a valid range");
            }
            cout << ans.i2 << endl;
        } else if (!cmd.empty() && cmd[0] == '!') {
            long long pLL;
            if (!(cin >> pLL)) {
                finish(_pe, "malformed answer: expected index after '!'");
            }
            if (pLL < 1 || pLL > n) {
                finish(_pe, "answer index out of range");
            }
            int p = (int)pLL;
            if (p == posMax) finish(_ok, "correct");
            finish(_wa, "wrong maximum position");
        } else {
            finish(_pe, "unexpected 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());
}

static void maybe_log_progress() {
    if (queries <= 1000 || (queries % 1000 == 0)) log_metrics();
}

struct SegTree {
    struct Node {
        int v1 = INT_MIN, i1 = -1;
        int v2 = INT_MIN, i2 = -1;
    };
    int n = 0;
    vector<Node> st;

    static void upd(Node& cur, int v, int idx) {
        if (idx == -1) return;
        if (cur.i1 == idx) {
            cur.v1 = max(cur.v1, v);
            return;
        }
        if (cur.i2 == idx) {
            cur.v2 = max(cur.v2, v);
            return;
        }
        if (v > cur.v1) {
            cur.v2 = cur.v1; cur.i2 = cur.i1;
            cur.v1 = v; cur.i1 = idx;
        } else if (v > cur.v2) {
            cur.v2 = v; cur.i2 = idx;
        }
    }

    static Node mergeNodes(const Node& a, const Node& b) {
        Node res;
        upd(res, a.v1, a.i1);
        upd(res, a.v2, a.i2);
        upd(res, b.v1, b.i1);
        upd(res, b.v2, b.i2);
        return res;
    }

    void init(const vector<int>& arr1indexed) {
        n = (int)arr1indexed.size() - 1;
        st.assign(4 * n + 4, Node());
        build(1, 1, n, arr1indexed);
    }

    void build(int p, int l, int r, const vector<int>& a) {
        if (l == r) {
            st[p].v1 = a[l];
            st[p].i1 = l;
            st[p].v2 = INT_MIN;
            st[p].i2 = -1;
            return;
        }
        int m = (l + r) >> 1;
        build(p << 1, l, m, a);
        build(p << 1 | 1, m + 1, r, a);
        st[p] = mergeNodes(st[p << 1], st[p << 1 | 1]);
    }

    Node query(int p, int l, int r, int ql, int qr) const {
        if (ql <= l && r <= qr) return st[p];
        int m = (l + r) >> 1;
        if (qr <= m) return query(p << 1, l, m, ql, qr);
        if (ql > m) return query(p << 1 | 1, m + 1, r, ql, qr);
        Node left = query(p << 1, l, m, ql, qr);
        Node right = query(p << 1 | 1, m + 1, r, ql, qr);
        return mergeNodes(left, right);
    }

    
    int secondMaxIndex(int l, int r) const {
        Node nd = query(1, 1, n, l, r);
        return nd.i2;
    }
};

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

    int n = inf.readInt(2, 100000, "n");

    vector<int> rest;
    while (!inf.seekEof()) {
        rest.push_back(inf.readInt());
    }

    bool non_adaptive = false;
    vector<int> a; 
    int pMax = -1; 
    int pFixed = -1;

    if ((int)rest.size() == n) {
        non_adaptive = true;
        a.assign(n + 1, 0);
        for (int i = 1; i <= n; i++) a[i] = rest[i - 1];
        int bestVal = INT_MIN;
        for (int i = 1; i <= n; i++) {
            if (a[i] > bestVal) {
                bestVal = a[i];
                pMax = i;
            }
        }
        if (pMax == -1) finish(_fail, "failed to determine maximum position from array");
    } else if ((int)rest.size() == 1) {
        non_adaptive = false;
        pFixed = rest[0];
        if (pFixed < 1 || pFixed > n) finish(_fail, "invalid p in adaptive input");
        pMax = pFixed;
    } else {
        finish(_fail, "unexpected input schema: expected n ints (non-adaptive) or 1 int (adaptive) after n");
    }

    query_limit = 40;
    log_metrics(); 

    
    cout << n << endl;

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

    SegTree st;
    if (non_adaptive) st.init(a);

    
    
    
    int dir = 0;

    while (true) {
        string tok;
        if (!(cin >> tok)) {
            finish(_pe, "unexpected EOF from participant");
        }

        if (tok == "?") {
            long long lll, rll;
            if (!(cin >> lll >> rll)) finish(_pe, "malformed query: expected '? l r'");
            if (lll < 1 || rll > n || lll >= rll) finish(_pe, "query out of bounds or invalid (need 1<=l<r<=n)");

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

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

            int ans = -1;
            if (non_adaptive) {
                ans = st.secondMaxIndex(l, r);
                if (ans < l || ans > r) finish(_fail, "internal error: computed answer out of range");
            } else {
                if (dir == 0) {
                    
                    dir = (l <= pMax && pMax <= r) ? -1 : +1;
                }

                bool hasP = (l <= pMax && pMax <= r);
                if (dir == +1) {
                    if (hasP) {
                        ans = r;
                        if (ans == pMax) ans--;
                    } else {
                        ans = r - 1;
                    }
                } else { 
                    if (hasP) {
                        ans = l;
                        if (ans == pMax) ans++;
                    } else {
                        ans = l + 1;
                    }
                }

                if (!(l <= ans && ans <= r) || ans == -1) finish(_fail, "internal error: adaptive answer invalid");
            }

            cout << ans << endl;
        } else if (tok == "!") {
            long long xll;
            if (!(cin >> xll)) finish(_pe, "malformed answer: expected '! p'");
            if (xll < 1 || xll > n) finish(_pe, "final answer out of range");

            int x = (int)xll;
            if (x == pMax) finish(_ok, "correct");
            finish(_wa, "wrong maximum position");
        } else {
            finish(_pe, "unknown token (expected '?' or '!')");
        }
    }
}


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

static void shuffleVec(vector<int>& v) {
    for (int i = (int)v.size() - 1; i > 0; --i) {
        int j = rnd.next(0, i);
        swap(v[i], v[j]);
    }
}

static vector<int> buildWithFixedTop2(int n, int posMax, int posSecond, int fillMode) {
    
    
    
    
    
    vector<int> a(n + 1, -1);
    if (n == 2) {
        a[posMax] = 2;
        a[posSecond] = 1;
        return a;
    }

    vector<int> rem;
    rem.reserve(max(0, n - 2));
    for (int x = 1; x <= n - 2; ++x) rem.push_back(x);

    if (fillMode == 0) {
        shuffleVec(rem);
    } else if (fillMode == 1) {
        
    } else if (fillMode == 2) {
        reverse(rem.begin(), rem.end());
    } else if (fillMode == 3) {
        vector<int> alt;
        alt.reserve(rem.size());
        int l = 0, r = (int)rem.size() - 1;
        while (l <= r) {
            alt.push_back(rem[l++]);
            if (l <= r) alt.push_back(rem[r--]);
        }
        rem.swap(alt);
    }

    int ptr = 0;
    for (int i = 1; i <= n; ++i) {
        if (i == posMax || i == posSecond) continue;
        a[i] = rem[ptr++];
    }
    a[posSecond] = n - 1;
    a[posMax] = n;

    return a;
}

struct Instance {
    int n = 0;
    int p = 0;              
    vector<int> a;          
};

static Instance makeInstance(int seed, int nOpt, int maxN) {
    Instance inst;

    auto clampN = [&](int x) -> int {
        if (x < 2) x = 2;
        if (x > maxN) x = maxN;
        return x;
    };

    int n;
    if (nOpt != -1) {
        n = clampN(nOpt);
    } else {
        if (seed == 1) n = 2;
        else if (seed == 2) n = maxN;
        else if (seed == 3) n = maxN;
        else {
            
            int roll = rnd.next(1, 10);
            if (roll <= 8) n = maxN;
            else n = rnd.next(2, maxN);
        }
    }
    inst.n = n;

    if (seed == 1) {
        
        inst.p = 1;
        inst.a = buildWithFixedTop2(n, 1, 2, 1);
        return inst;
    }
    if (seed == 2) {
        
        inst.p = n;
        inst.a.assign(n + 1, 0);
        for (int i = 1; i <= n; ++i) inst.a[i] = i;
        return inst;
    }
    if (seed == 3) {
        
        inst.p = n;
        inst.a = buildWithFixedTop2(n, n, 1, 3);
        return inst;
    }

    int type = rnd.next(1, 6);
    if (type == 1) {
        
        int posMax = 1;
        int posSecond = n;
        inst.p = posMax;
        inst.a = buildWithFixedTop2(n, posMax, posSecond, 0);
    } else if (type == 2) {
        
        int posMax = n;
        int posSecond = 1;
        inst.p = posMax;
        inst.a = buildWithFixedTop2(n, posMax, posSecond, 3);
    } else if (type == 3) {
        
        int posMax = (n + 1) / 2;
        int posSecond = posMax + 1;
        if (posSecond > n) posSecond = posMax - 1;
        if (posSecond < 1) posSecond = (posMax == 1 ? 2 : 1);
        inst.p = posMax;
        inst.a = buildWithFixedTop2(n, posMax, posSecond, 2);
    } else if (type == 4) {
        
        vector<int> v(n);
        for (int i = 0; i < n; ++i) v[i] = i + 1;
        shuffleVec(v);
        inst.a.assign(n + 1, 0);
        for (int i = 1; i <= n; ++i) inst.a[i] = v[i - 1];
        for (int i = 1; i <= n; ++i) if (inst.a[i] == n) inst.p = i;
    } else if (type == 5) {
        
        int posMax = rnd.next(1, n);
        int posSecond = rnd.next(1, n - 1);
        if (posSecond >= posMax) posSecond++;
        inst.p = posMax;
        inst.a = buildWithFixedTop2(n, posMax, posSecond, 1);
        
        int L = rnd.next(1, n);
        int R = rnd.next(1, n);
        if (L > R) swap(L, R);
        if (!(L <= posMax && posMax <= R) && !(L <= posSecond && posSecond <= R) && R - L + 1 >= 2) {
            reverse(inst.a.begin() + L, inst.a.begin() + R + 1);
        }
    } else {
        
        int posMax = rnd.next(1, n);
        int posSecond;
        if (posMax == 1) posSecond = n;
        else if (posMax == n) posSecond = 1;
        else posSecond = (rnd.next(0, 1) ? 1 : n);
        inst.p = posMax;
        inst.a = buildWithFixedTop2(n, posMax, posSecond, 3);
    }

    if (inst.p < 1 || inst.p > n) {
        
        inst.p = n;
        inst.a.assign(n + 1, 0);
        for (int i = 1; i <= n; ++i) inst.a[i] = i;
    }
    return inst;
}

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

    string mode = opt<string>("mode", "non");
    int maxN = opt<int>("maxn", 100000);
    if (maxN < 2) maxN = 2;
    if (maxN > 100000) maxN = 100000;

    int nOpt = opt<int>("n", -1);

    int seed = 0;
    if (argc >= 2) seed = atoi(argv[1]);

    Instance inst = makeInstance(seed, nOpt, maxN);

    if (mode == "non") {
        cout << inst.n << "\n";
        for (int i = 1; i <= inst.n; ++i) {
            if (i > 1) cout << ' ';
            cout << inst.a[i];
        }
        cout << "\n";
    } else if (mode == "adp") {
        
        cout << inst.n << "\n" << inst.p << "\n";
    } else {
        quitf(_fail, "unknown mode: %s", mode.c_str());
    }

    return 0;
}