Problem: cf2111_g
Difficulty: medium
Categories: data structures
Time limit: 7000 ms, memory limit: 1024 MB

Technically, this is an interactive problem.

An array $a$ of $m$ numbers is called divisible if at least one of the following conditions holds:

* There exists an index $i$ ($1 \le i < m$) and an integer $x$ such that for all indices $j$ ($j \le i$), it holds that $a_{j} \le x$ and for all indices $k$ ($k > i$), it holds that $a_{k} > x$.
* There exists an index $i$ ($1 \le i < m$) and an integer $x$ such that for all indices $j$ ($j \le i$), it holds that $a_{j} > x$ and for all indices $k$ ($k > i$), it holds that $a_{k} \le x$.

You are given a permutation $p$ of integers $1, 2, \dots, n$. Your task is to answer queries of the following form fast: if we take only the segment [$l$, $r$] from the permutation, that is, the numbers $p_{l}, p_{l + 1}, \dots, p_{r}$, is this subarray of numbers divisible?

Queries will be submitted in interactive mode in groups of $10$, meaning you will not receive the next group of queries until you output all answers for the current group.

Input

The first line contains one integer $n$ ($2 \le n \le 2 \cdot 10^{5}$) — the size of the permutation.

The second line contains $n$ integers $p_{i}$ ($1 \le p_{i} \le n$) — the permutation of natural numbers itself.

The third line contains one integer $q$ ($10 \le q \le 10^{6}, q \bmod 10 = 0$) — the number of queries.

The following $q$ lines contain two integers $l$ and $r$ ($1 \le l < r \le n$) — the parameters of the query.

Output

For each query, output the string "YES" if the subarray from this query is divisible and "NO" otherwise.

After printing the answers to a group of queries, do not forget to output the end of line and flush the output buffer. Otherwise, you may get the Idleness Limit Exceeded verdict. To flush the buffer, use:

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

You have to flush the output buffer after the $10$-th, $20$-th, $30$-th query (and so on), i. e. after each query with index divisible by $10$. After that, you can read the next group of queries.

Example

Input

```
7

4 2 3 6 1 5 7

20

1 2

1 3

1 4

1 5

1 6

2 3

2 4

2 5

2 6

3 4

3 5

3 6

4 5

4 6

5 6

1 7

2 7

3 7

4 7

5 7
```

Output

```
YES
YES
YES
YES
NO
YES
YES
YES
NO
YES
YES
NO
YES
YES
YES
YES
YES
YES
YES
YES
```

Non-adaptive interactor (C++):














#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;


static long long queries_processed = 0;
static long long total_queries = 0; 


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


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


const int MAXN = 200005;
const int LOGN = 19;
int st_min[MAXN][LOGN];
int st_max[MAXN][LOGN];
int st_min_idx[MAXN][LOGN];
int st_max_idx[MAXN][LOGN];
int lg[MAXN];
int n;
vector<int> p;


void build_sparse() {
    lg[1] = 0;
    for (int i = 2; i <= n; i++) lg[i] = lg[i/2] + 1;
    
    for (int i = 1; i <= n; i++) {
        st_min[i][0] = p[i-1];
        st_max[i][0] = p[i-1];
        st_min_idx[i][0] = i;
        st_max_idx[i][0] = i;
    }
    
    for (int j = 1; j < LOGN; j++) {
        for (int i = 1; i + (1 << j) - 1 <= n; i++) {
            
            st_min[i][j] = min(st_min[i][j-1], st_min[i + (1 << (j-1))][j-1]);
            st_max[i][j] = max(st_max[i][j-1], st_max[i + (1 << (j-1))][j-1]);
            
            
            int idx1 = st_min_idx[i][j-1];
            int idx2 = st_min_idx[i + (1 << (j-1))][j-1];
            st_min_idx[i][j] = (p[idx1-1] < p[idx2-1]) ? idx1 : idx2;
            
            
            idx1 = st_max_idx[i][j-1];
            idx2 = st_max_idx[i + (1 << (j-1))][j-1];
            st_max_idx[i][j] = (p[idx1-1] > p[idx2-1]) ? idx1 : idx2;
        }
    }
}


int query_min(int l, int r) {
    if (l > r) return 1e9;
    int j = lg[r - l + 1];
    return min(st_min[l][j], st_min[r - (1 << j) + 1][j]);
}


int query_max(int l, int r) {
    if (l > r) return -1e9;
    int j = lg[r - l + 1];
    return max(st_max[l][j], st_max[r - (1 << j) + 1][j]);
}


int query_min_idx(int l, int r) {
    int j = lg[r - l + 1];
    int idx1 = st_min_idx[l][j];
    int idx2 = st_min_idx[r - (1 << j) + 1][j];
    return (p[idx1-1] < p[idx2-1]) ? idx1 : idx2;
}


int query_max_idx(int l, int r) {
    int j = lg[r - l + 1];
    int idx1 = st_max_idx[l][j];
    int idx2 = st_max_idx[r - (1 << j) + 1][j];
    return (p[idx1-1] > p[idx2-1]) ? idx1 : idx2;
}







bool check_type1(int l, int r) {
    int m = query_min_idx(l, r);
    if (m == r) return false; 
    
    int curr = m;
    int M = query_max(l, curr); 
    
    
    
    
    
    while (curr < r) {
        
        
        int low = curr, high = r - 1;
        int k = -1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (query_min(mid + 1, r) > M) {
                k = mid;
                high = mid - 1; 
            } else {
                low = mid + 1;
            }
        }
        
        if (k == -1) return false; 
        
        
        
        int new_M = query_max(l, k);
        
        
        if (new_M < query_min(k + 1, r)) return true;
        
        
        
        
        M = new_M;
        curr = k;
    }
    return false;
}





bool check_type2(int l, int r) {
    int m = query_max_idx(l, r);
    if (m == r) return false;
    
    int curr = m;
    int MN = query_min(l, curr); 
    
    
    
    
    while (curr < r) {
        
        
        int low = curr, high = r - 1;
        int k = -1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (query_max(mid + 1, r) < MN) {
                k = mid;
                high = mid - 1; 
            } else {
                low = mid + 1;
            }
        }
        
        if (k == -1) return false;
        
        int new_MN = query_min(l, k);
        if (new_MN > query_max(k + 1, r)) return true;
        
        MN = new_MN;
        curr = k;
    }
    return false;
}

bool solve(int l, int r) {
    if (l >= r) return false;
    return check_type1(l, r) || check_type2(l, r);
}


int main(int argc, char* argv[]) {
    
    registerInteraction(argc, argv);
    atexit(log_metrics);
    
    
    n = inf.readInt(2, 200000, "n");
    p.resize(n);
    for (int i = 0; i < n; i++) {
        p[i] = inf.readInt(1, n, "p_i");
    }
    int q = inf.readInt(10, 1000000, "q");
    total_queries = q;
    
    
    struct Query { int l, r; };
    vector<Query> all_queries(q);
    for (int i = 0; i < q; i++) {
        all_queries[i].l = inf.readInt(1, n, "l");
        all_queries[i].r = inf.readInt(all_queries[i].l + 1, n, "r");
    }
    
    
    build_sparse();
    
    
    cout << n << endl;
    for (int i = 0; i < n; i++) {
        cout << p[i] << (i == n - 1 ? "" : " ");
    }
    cout << endl;
    cout << q << endl;
    
    
    int group_size = 10;
    for (int i = 0; i < q; i += group_size) {
        int current_group_end = min(q, i + group_size);
        int current_group_count = current_group_end - i;
        
        
        for (int j = i; j < current_group_end; j++) {
            cout << all_queries[j].l << " " << all_queries[j].r << "\n";
        }
        cout.flush();
        
        
        for (int j = i; j < current_group_end; j++) {
            string token = ouf.readToken("YES|NO"); 
            bool ans = (token == "YES");
            
            bool expected = solve(all_queries[j].l, all_queries[j].r);
            
            if (ans != expected) {
                finish(_wa, format("Wrong answer for query %d (Expected %s, Got %s)", 
                                   j + 1, expected ? "YES" : "NO", token.c_str()));
            }
            queries_processed++;
        }
    }
    
    finish(_ok, "All queries answered correctly");
}


Adaptive interactor (C++):

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

using namespace std;







vector<int> get_permutation(int n, int type) {
    vector<int> p(n);
    if (type == 0) {
        iota(p.begin(), p.end(), 1);
        shuffle(p.begin(), p.end());
    } else if (type == 1) {
        iota(p.begin(), p.end(), 1);
    } else if (type == 2) {
        iota(p.begin(), p.end(), 1);
        reverse(p.begin(), p.end());
    } else if (type == 3) {
        
        
        vector<int> left, right;
        for (int i = 1; i <= n; i++) {
            if (rnd.next(2)) left.push_back(i);
            else right.push_back(i);
        }
        sort(left.rbegin(), left.rend());
        sort(right.begin(), right.end());
        int idx = 0;
        for (int x : left) p[idx++] = x;
        for (int x : right) p[idx++] = x;
    } else {
        
        int L = 1, R = n;
        for (int i = 0; i < n; i++) {
            if (i % 2 == 0) p[i] = L++;
            else p[i] = R--;
        }
        
        if (rnd.next(2)) {
            for(int &x : p) x = n - x + 1;
        }
    }
    return p;
}

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);
    
    
    string mode = opt<string>("mode", "non");
    int n_arg = opt<int>("n", -1);
    int q_arg = opt<int>("q", -1);
    
    
    int seed = atoi(argv[1]);
    
    
    int n;
    if (n_arg != -1) n = n_arg;
    else {
        
        if (seed <= 5) n = rnd.next(10, 100);
        else n = rnd.next(100000, 200000);
    }
    
    
    int q;
    if (q_arg != -1) q = q_arg;
    else {
        if (seed <= 5) q = rnd.next(1, 10) * 10; 
        else q = rnd.next(50000, 100000) * 10;  
    }
    
    
    q = (q / 10) * 10;
    if (q < 10) q = 10;
    
    if (q > 1000000) q = 1000000;

    
    int type = 0;
    if (mode == "adp") {
        
        
        type = rnd.next(3, 4); 
    } else {
        
        if (seed == 1) type = 1;      
        else if (seed == 2) type = 2; 
        else if (seed == 3) type = 3; 
        else type = 0;                
        
        
        if (seed > 10 && rnd.next(5) == 0) type = rnd.next(1, 4);
    }
    
    
    vector<int> p = get_permutation(n, type);
    
    
    cout << n << endl;
    
    
    for (int i = 0; i < n; i++) {
        cout << p[i] << (i == n - 1 ? "" : " ");
    }
    cout << endl;
    
    
    cout << q << endl;
    
    
    for (int i = 0; i < q; i++) {
        int l, r;
        int s = rnd.next(100);
        
        
        if (s < 20) {
            
            int max_len = min(n, 20);
            int len = rnd.next(2, max_len);
            l = rnd.next(1, n - len + 1);
            r = l + len - 1;
        } else if (s < 50) {
            
            int min_len = min(n, 10);
            int max_len = min(n, (int)sqrt(n) + 100);
            
            if (min_len > max_len) swap(min_len, max_len);
            
            int len = rnd.next(min_len, max_len);
            l = rnd.next(1, n - len + 1);
            r = l + len - 1;
        } else if (s < 80) {
            
            
            l = rnd.next(1, n / 2);
            r = rnd.next(n / 2 + 1, n);
        } else {
            
            int margin = max(1, n / 20);
            l = rnd.next(1, margin);
            r = rnd.next(n - margin + 1, n);
            
            if (l >= r) { l = 1; r = n; }
        }
        cout << l << " " << r << "\n";
    }

    return 0;
}