|
|
#include <cstdio>
|
|
|
#include <algorithm>
|
|
|
using namespace std;
|
|
|
const int N = 5e5 + 10;
|
|
|
const int M = N * 32;
|
|
|
struct Node {
|
|
|
int l, r, cnt; //[l,r]管辖范围,cnt:区间中元素个数和
|
|
|
} tr[M];
|
|
|
|
|
|
int n, m;
|
|
|
int root[N], idx;
|
|
|
int read() {
|
|
|
int x = 0, f = 1;
|
|
|
char ch = getchar();
|
|
|
while (ch < '0' || ch > '9') {
|
|
|
if (ch == '-') f = -1;
|
|
|
ch = getchar();
|
|
|
}
|
|
|
while ('0' <= ch && ch <= '9') {
|
|
|
x = (x << 3) + (x << 1) + (ch ^ 48);
|
|
|
ch = getchar();
|
|
|
}
|
|
|
return x * f;
|
|
|
}
|
|
|
|
|
|
//经典的主席树插入
|
|
|
void insert(int &u, int l, int r, int x) {
|
|
|
tr[++idx] = tr[u]; //新开一个节点idx++,将新节点指向旧的tr[u]
|
|
|
u = idx; //因为是引用,为了回传正确值,需要u=idx-1
|
|
|
tr[u].cnt++; //新节点的cnt,因为多插入了一个数字,所以个数+1,这样处理的话,省去了pushup
|
|
|
if (l == r) return; //如果已经到了叶子节点,上面的操作就足够了,可以直接返回,否则需要继续向下递归
|
|
|
|
|
|
int mid = (l + r) >> 1;
|
|
|
if (x <= mid)
|
|
|
insert(tr[u].l, l, mid, x); //因为tr[u]进入本函数时,最先把旧的复制过来,所以tr[u].l也是上一个版本的左儿子节点
|
|
|
else
|
|
|
insert(tr[u].r, mid + 1, r, x);
|
|
|
}
|
|
|
|
|
|
int query(int p, int q, int l, int r, int x) {
|
|
|
if (l == r) return l;
|
|
|
int mid = (l + r) >> 1;
|
|
|
//使用*2的办法,成功的躲开了除以2可能会丢失精度的问题
|
|
|
//对位相减
|
|
|
if (2 * (tr[tr[q].l].cnt - tr[tr[p].l].cnt) > x)
|
|
|
return query(tr[p].l, tr[q].l, l, mid, x);
|
|
|
if (2 * (tr[tr[q].r].cnt - tr[tr[p].r].cnt) > x)
|
|
|
return query(tr[p].r, tr[q].r, mid + 1, r, x);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
//文件输入输出
|
|
|
#ifndef ONLINE_JUDGE
|
|
|
freopen("P3567.in", "r", stdin);
|
|
|
#endif
|
|
|
n = read(), m = read();
|
|
|
|
|
|
// 0号版本没有内容时,主席树是不需要进行build的,强行build时,可能会有部分测试点TLE
|
|
|
// 0号版本有内容时,主席树是需要build的,不build,初始值无法给上
|
|
|
|
|
|
for (int i = 1; i <= n; i++) {
|
|
|
//不断的读入数字,不断的加入到主席树中,不断的创新新的版本
|
|
|
//新版本按套路来看,都要先从上一个版本中继承过来
|
|
|
int x = read();
|
|
|
root[i] = root[i - 1];
|
|
|
//依托于旧版本,插入数字x,并且,由于第一个参数是按地址引用的,所以新生成的节点号,会重写到root[i]
|
|
|
insert(root[i], 1, n, x);
|
|
|
}
|
|
|
|
|
|
while (m--) {
|
|
|
int l = read(), r = read();
|
|
|
printf("%d\n", query(root[l - 1], root[r], 1, n, r - l + 1));
|
|
|
}
|
|
|
return 0;
|
|
|
} |