「学习笔记」数列分块入门 1 ~ 9
一天多一点的时间, 做完了这 \(9\) 道题, 除了最后一道题之外, 都感觉良好.
这里是 黄学长的博客.
数列分块入门 1
区间加法, 单点查值. 很入门的题目了.
暴力处理两边不完整的块, 完整的块维护一个 tag
加法标记.
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 5e4 + 5;
int n, len;
int be[N];
ll val[N], tag[N];
void add(int l, int r, int c) {
int lim = min(r, be[l] * len);
for (int i = l; i <= lim; ++ i) {
val[i] += c;
}
if (be[l] != be[r]) {
for (int i = (be[r] - 1) * len + 1; i <= r; ++ i) {
val[i] += c;
}
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
tag[i] += c;
}
}
int main() {
n = read<int>(), len = sqrt(n);
for (int i = 1; i <= n; ++ i) {
val[i] = read<ll>();
}
for (int i = 1; i <= n; ++ i) {
be[i] = (i - 1) / len + 1;
}
while (n --) {
int op = read<int>(), a = read<int>(), b = read<int>(), c = read<int>();
if (op == 0) {
add(a, b, c);
}
else {
printf("%lld\n", val[b] + tag[be[b]]);
}
}
return 0;
}
数列分块入门 2
区间加法, 查询区间内小于某个值的元素个数.
用 vector
和 sort
就可以解决, 我一开始用的 set
, 后来发现没法获取数组下标.
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define le(i) ((i - 1) * len + 1)
#define re(i) (i * len)
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 5e4 + 5;
const int inf = (1 << 31);
const int INF = ~(1 << 31);
int n, len;
int be[N];
int val[N], tag[N], mx[N], mn[N];
inline void add(int l, int r, ll c) {
int lim = min(r, re(be[l]));
for (int i = l; i <= lim; ++ i) {
val[i] += c;
mx[be[l]] = max(mx[be[l]], val[i]);
mn[be[l]] = min(mn[be[l]], val[i]);
}
if (be[l] == be[r]) return ;
for (int i = le(be[r]); i <= r; ++ i) {
val[i] += c;
mx[be[r]] = max(mx[be[r]], val[i]);
mn[be[r]] = min(mn[be[r]], val[i]);
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
tag[i] += c;
}
}
inline int ask(int l, int r, ll c) {
int ans = 0, lim = min(r, re(be[l]));
for (int i = l; i <= lim; ++ i) {
if (mn[be[l]] + tag[be[l]] >= c) {
break ;
}
if (mx[be[l]] + tag[be[l]] < c) {
ans += (lim - l + 1);
break ;
}
(val[i] + tag[be[l]] < c) ? ++ ans : ans;
}
if (be[l] == be[r]) return ans;
for (int i = le(be[r]); i <= r; ++ i) {
if (mn[be[r]] + tag[be[r]] >= c) {
break ;
}
if (mx[be[r]] + tag[be[r]] < c) {
ans += (r - le(be[r]) + 1);
break ;
}
(val[i] + tag[be[r]] < c) ? ++ ans : ans;
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
if (mn[i] + tag[i] >= c) {
continue ;
}
if (mx[i] + tag[i] < c) {
ans += len;
continue ;
}
for (int j = le(i); j <= re(i); ++ j) {
(val[j] + tag[i] < c) ? ++ ans : ans;
}
}
return ans;
}
int main() {
n = read<int>(), len = sqrt(n);
memset(mx, 128, sizeof mx);
memset(mn, 127, sizeof mn);
for (int i = 1; i <= n; ++ i) {
val[i] = read<ll>();
be[i] = (i - 1) / len + 1;
mx[be[i]] = max(mx[be[i]], val[i]);
mn[be[i]] = min(mn[be[i]], val[i]);
}
for (int i = 1; i <= n; ++ i) {
int op = read<int>(), a = read<int>(), b = read<int>(), c = read<int>();
if (op == 0) {
add(a, b, c);
}
else {
printf("%d\n", ask(a, b, c * c));
}
}
return 0;
}
数列分块入门 3
区间加法, 找前驱.
这已经是平衡树的操作了, 但是这里我们不写平衡树 我也已经忘了咋写了 =_= ||, 采取在块上二分的方法.
这里有 set
和 vector
两种写法.
vector
写法
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define le(i) ((i - 1) * len + 1)
#define re(i) (i * len)
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 1e5 + 5;
int n, len;
int be[N];
int val[N], tag[N];
vector<int> s[510];
inline void reset(int x) {
s[x].clear();
for (int i = le(x); i <= re(x); ++ i) {
s[x].emplace_back(val[i]);
}
sort(s[x].begin(), s[x].end());
}
inline void add(int l, int r, ll c) {
int lim = min(r, re(be[l]));
for (int i = l; i <= lim; ++ i) {
val[i] += c;
}
reset(be[l]);
if (be[l] == be[r]) return ;
for (int i = le(be[r]); i <= r; ++ i) {
val[i] += c;
}
reset(be[r]);
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
tag[i] += c;
}
}
inline int ask(int l, int r, ll c) {
int ans = -1;
int lim = min(r, re(be[l]));
for (int i = l; i <= lim; ++ i) {
int tmp = val[i] + tag[be[l]];
if (tmp < c) {
ans = max(ans, tmp);
}
if (ans == c - 1) {
return ans;
}
}
if (be[l] == be[r]) return ans;
for (int i = le(be[r]); i <= r; ++ i) {
int tmp = val[i] + tag[be[r]];
if (tmp < c) {
ans = max(ans, tmp);
}
if (ans == c - 1) {
return ans;
}
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
if (*s[i].begin() + tag[i] >= c) continue ;
int pos = lower_bound(s[i].begin(), s[i].end(), c - tag[i]) - s[i].begin();
ans = max(ans, s[i][pos - 1] + tag[i]);
if (ans == c - 1) {
return ans;
}
}
return ans;
}
int main() {
n = read<int>(), len = sqrt(n);
for (int i = 1; i <= n; ++ i) {
val[i] = read<ll>();
be[i] = (i - 1) / len + 1;
s[be[i]].emplace_back(val[i]);
}
for (int i = 1; i <= len; ++ i) {
sort(s[i].begin(), s[i].end());
}
for (int i = 1; i <= n; ++ i) {
int op = read<int>(), a = read<int>(), b = read<int>(), c = read<int>();
if (op == 0) {
add(a, b, c);
}
else {
printf("%d\n",ask(a, b, c));
}
}
return 0;
}
set
写法
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define le(i) ((i - 1) * len + 1)
#define re(i) (i * len)
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 1e5 + 5;
int n, len;
int be[N];
ll val[N], tag[N];
multiset<ll> s[1100];
void add(int l, int r, ll c) {
int lim = min(r, re(be[l]));
for (int i = l; i <= lim; ++ i) {
s[be[l]].erase(val[i]);
val[i] += c;
s[be[l]].insert(val[i]);
}
if (be[l] == be[r]) return ;
for (int i = le(be[r]); i <= r; ++ i) {
s[be[r]].erase(val[i]);
val[i] += c;
s[be[r]].insert(val[i]);
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
tag[i] += c;
}
}
ll ask(int l, int r, ll c) {
ll ans = -1;
int lim = min(r, re(be[l]));
for (int i = l; i <= lim; ++ i) {
ll tmp = val[i] + tag[be[l]];
if (tmp < c) {
ans = max(ans, tmp);
}
}
if (be[l] == be[r]) return ans;
for (int i = le(be[r]); i <= r; ++ i) {
ll tmp = val[i] + tag[be[r]];
if (tmp < c) {
ans = max(ans, tmp);
}
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
ll tmp = c - tag[i];
set<ll> :: iterator it = s[i].lower_bound(tmp);
if (it == s[i].begin()) {
continue ;
}
-- it;
ans = max(ans, *it + tag[i]);
}
return ans;
}
int main() {
n = read<int>(), len = sqrt(n);
for (int i = 1; i <= n; ++ i) {
val[i] = read<ll>();
be[i] = (i - 1) / len + 1;
s[be[i]].insert(val[i]);
}
for (int i = 1; i <= n; ++ i) {
int op = read<int>(), a = read<int>(), b = read<int>(), c = read<int>();
if (op == 0) {
add(a, b, c);
}
else {
printf("%lld\n", ask(a, b, c));
}
}
return 0;
}
数列分块入门 4
区间加法, 区间求和.
暴力处理两边不完整的块, 完整的块记录总和与加法标记, 类似于线段树的操作.
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define le(i) ((i - 1) * len + 1)
#define re(i) (i * len)
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 50010;
int n, len;
int be[N];
ll val[N], tag[N], sum[510];
inline void add(int l, int r, ll c) {
int lim = min(r, re(be[l]));
for (int i = l; i <= lim; ++ i) {
val[i] += c;
sum[be[l]] += c;
}
if (be[l] == be[r]) return ;
for (int i = le(be[r]); i <= r; ++ i) {
val[i] += c;
sum[be[r]] += c;
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
tag[i] += c;
}
}
inline ll ask(int l, int r, ll c) {
ll res = 0;
int lim = min(r, re(be[l]));
for (int i = l; i <= lim; ++ i) {
res = (res + val[i] + tag[be[l]]) % c;
}
if (be[l] == be[r]) return res;
for (int i = le(be[r]); i <= r; ++ i) {
res = (res + val[i] + tag[be[r]]) % c;
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
res = (res + sum[i] + tag[i] * len) % c;
}
return res;
}
int main() {
n = read<int>(), len = sqrt(n);
for (int i = 1; i <= n; ++ i) {
val[i] = read<int>();
be[i] = (i - 1) / len + 1;
sum[be[i]] += val[i];
}
for (int i = 1, op, l, r, c; i <= n; ++ i) {
op = read<int>(), l = read<int>(), r = read<int>(), c = read<int>();
if (op == 0) {
add(l, r, c);
}
else {
printf("%lld\n", ask(l, r, c + 1));
}
}
return 0;
}
数列分块入门 5
区间开方, 区间求和.
一个 long long
范围的数, 最多开 \(6\) 次平方就会变成 \(1\) 或 \(0\), 修改时暴力修改, 维护一个 tag
, 表示这个区间内的数是否都小于等于 \(1\).
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 50010;
int n, len;
int be[N], le[510], re[510];
ll val[N], sum[510];
bool none[510];
void Reset(int x, int need) {
if (none[x]) return ;
none[x] = 1;
sum[x] = 0;
for (int i = le[x]; i <= re[x]; ++ i) {
if (need) {
val[i] = floor(sqrt(val[i]));
}
sum[x] += val[i];
if (val[i] > 1) {
none[x] = 0;
}
}
}
void kf(int l, int r) {
int lim = min(re[be[l]], r);
if (!none[be[l]]) {
for (int i = l; i <= lim; ++ i) {
val[i] = floor(sqrt(val[i]));
}
Reset(be[l], 0);
}
if (be[l] == be[r]) return ;
if (!none[be[r]]) {
for (int i = le[be[r]]; i <= r; ++ i) {
if (none[be[r]]) break ;
val[i] = floor(sqrt(val[i]));
}
Reset(be[r], 0);
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
if (none[i]) continue ;
Reset(i, 1);
}
}
int ask(int l, int r) {
int lim = min(r, re[be[l]]), ans = 0;
for (int i = l; i <= lim; ++ i) {
ans += val[i];
}
if (be[l] == be[r]) return ans;
for (int i = le[be[r]]; i <= r; ++ i) {
ans += val[i];
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
if (none[i]) {
ans += sum[i];
continue ;
}
for (int j = le[i]; j <= re[i]; ++ j) {
ans += val[j];
}
}
return ans ;
}
int main() {
n = read<int>(), len = sqrt(n);
for (int i = 1; i <= n; ++ i) {
val[i] = read<ll>();
be[i] = (i - 1) / len + 1;
le[be[i]] = re[be[i] - 1] + 1;
re[be[i]] = min(n, be[i] * len);
sum[be[i]] += val[i];
}
for (int i = 1, op, l, r, c; i <= n; ++ i) {
op = read<int>(), l = read<int>(), r = read<int>(), c = read<int>();
if (op == 0) {
kf(l, r);
}
else {
printf("%d\n", ask(l, r));
}
}
return 0;
}
数列分块入门 6
单点插入, 单点询问.
好像也算是平衡树的操作吧, 我们这里将平时分块用的数组改为可以改变长度的 vector
, 插入操作可以使用 insert
来实现, 随机数据下这样就可以过了, 非随机数据下, 如果一个块的长度太大了, 我们需要重构块.
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 2e5 + 5;
int n, len;
ll val[N];
vector<int> kuai[510];
pii Find(int pos) {
int k = 1;
while (pos > (int)kuai[k].size()) {
pos -= (int)kuai[k].size();
++ k;
}
return {k, pos - 1};
}
void rebuild() {
int cnt = 0;
for (int i = 1; i <= len + 1; ++ i) {
if (kuai[i].empty()) break;
for (int v : kuai[i]) {
val[++ cnt] = v;
}
kuai[i].clear();
}
len = sqrt(cnt);
for (int i = 1; i <= cnt; ++ i) {
kuai[(i - 1) / len + 1].emplace_back(val[i]);
}
}
void Insert(int pos, int c) {
pii it = Find(pos);
kuai[it.first].insert(kuai[it.first].begin() + it.second, c);
if ((int)kuai[it.first].size() >= (7 * len)) {
rebuild();
}
}
int main() {
n = read<int>(), len = sqrt(n);
for (int i = 1; i <= n; ++ i) {
val[i] = read<ll>();
kuai[(i - 1) / len + 1].emplace_back(val[i]);
}
for (int i = 1, op, l, r, c; i <= n; ++ i) {
op = read<int>(), l = read<int>(), r = read<int>(), c = read<int>();
if (op == 0) {
Insert(l, r);
}
else {
pii it = Find(r);
cout << kuai[it.first][it.second] << '\n';
}
}
return 0;
}
数列分块入门 7
区间加法 + 区间乘法 + 单点查询.
我们需要维护两个 tag
, 要注意两个顺序, 先加后乘, 我们需要把加法 tag
里面的数也进行乘法, 先乘后加就不用, 再进行操作前都需要对块进行下放标记的操作.
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 1e5 + 5;
const int mod = 10007;
int n, len;
int be[N], le[510], re[510];
ll val[N], tag1[510], tag2[510];
inline void pushup(int x) {
for (int i = le[x]; i <= re[x]; ++ i) {
val[i] = (val[i] * tag2[x] + tag1[x]) % mod;
}
tag2[x] = 1, tag1[x] = 0;
}
void add(int l, int r, ll c) {
int lim = min(r, re[be[l]]);
pushup(be[l]);
for (int i = l; i <= lim; ++ i) {
val[i] = (val[i] + c) % mod;
}
if (be[l] == be[r]) return ;
pushup(be[r]);
for (int i = le[be[r]]; i <= r; ++ i) {
val[i] = (val[i] + c) % mod;
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
tag1[i] = (tag1[i] + c) % mod;
}
}
void times(int l, int r, ll c) {
int lim = min(r, re[be[l]]);
pushup(be[l]);
for (int i = l; i <= lim; ++ i) {
val[i] = val[i] * c % mod;
}
if (be[l] == be[r]) return ;
pushup(be[r]);
for (int i = le[be[r]]; i <= r; ++ i) {
val[i] = val[i] * c % mod;
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
tag1[i] = tag1[i] * c % mod;
tag2[i] = tag2[i] * c % mod;
}
}
ll ask(int x) {
return (val[x] * tag2[be[x]] + tag1[be[x]]) % mod;
}
int main() {
n = read<int>(), len = sqrt(n);
for (int i = 1; i <= n; ++ i) {
val[i] = read<ll>();
be[i] = (i - 1) / len + 1;
tag2[be[i]] = 1;
le[be[i]] = re[be[i] - 1] + 1;
re[be[i]] = min(n, be[i] * len);
}
for (int i = 1, op, l, r, c; i <= n; ++ i) {
op = read<int>(), l = read<int>(), r = read<int>(), c = read<int>();
if (op == 0) {
add(l, r, c);
}
else if (op == 1) {
times(l, r, c);
}
else {
printf("%lld\n", ask(r) % mod);
}
}
return 0;
}
数列分块入门 8
dzy 说:“分块大佬不做 \(8\) 和 \(9\)”, 我不是大佬, 所以, 我就做了 =_=||
区间修改和查询相同元素的个数, 有预处理操作, 对于不完整的块暴力修改, 完整的块打标记.
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 1e5 + 5;
int n, len;
int be[N], tag[510], le[510], re[510];
ll val[N];
void Reset(int x) {
if (tag[x] == -1) return ;
for (int i = le[x]; i <= re[x]; ++ i) {
val[i] = tag[x];
}
tag[x] = -1;
}
int work(int l, int r, int c) {
int lim = min(r, re[be[l]]), ans = 0;
Reset(be[l]);
for (int i = l; i <= lim; ++ i) {
ans += (val[i] == c);
val[i] = c;
}
if (be[l] == be[r]) return ans;
Reset(be[r]);
for (int i = le[be[r]]; i <= r; ++ i) {
ans += (val[i] == c);
val[i] = c;
}
for (int i = be[l] + 1; i <= be[r] - 1; ++ i) {
if (tag[i] == c) {
ans += (re[i] - le[i] + 1);
}
else if (tag[i] == -1) {
for (int j = le[i]; j <= re[i]; ++ j) {
ans += (val[j] == c);
}
}
tag[i] = c;
}
return ans;
}
int main() {
n = read<int>(), len = sqrt(n);
for (int i = 1; i <= n; ++ i) {
val[i] = read<int>();
be[i] = (i - 1) / len + 1;
tag[be[i]] = -1;
le[be[i]] = re[be[i] - 1] + 1;
re[be[i]] = min(n, be[i] * len);
}
for (int i = 1, l, r, c; i <= n; ++ i) {
l = read<int>(), r = read<int>(), c = read<int>();
printf("%d\n", work(l, r, c));
}
return 0;
}
数列分块入门 9
区间中位数, 我不太会, 这个题被卡出阴影了.
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 2e5 + 10;
int n, len, cnt;
int be[N], le[N], re[N], cot[N];
pii f[510][510];
ll val[N];
vector<int> s[N], num;
pii check(pii a, pii b) {
if (b.first > a.first || (b.first == a.first && b.second < a.second)) {
return b;
}
return a;
}
void pre(int x) {
for (int i = 1; i <= n + 5; ++ i) {
cot[i] = 0;
}
int mx = 0, ans = 0;
for (int i = le[x]; i <= n; ++ i) {
cot[val[i]] ++;
pii it = check({mx, ans}, {cot[val[i]], val[i]});
mx = it.first, ans = it.second;
if (be[i] != be[i + 1]) {
f[i][be[i]] = {mx, ans};
}
}
}
pii Find(int l, int r, int lr, int rr) {
pii res;
for (int i = l; i <= r; ++ i) {
int num = val[i];
int posl = lower_bound(s[num].begin(), s[num].end(), lr) - s[num].begin();
int posr = upper_bound(s[num].begin(), s[num].end(), rr) - s[num].begin() - 1;
res = check(res, {posr - posl + 1, val[i]});
}
return res;
}
int ask(int l, int r) {
if (be[l] == be[r]) {
return Find(l, r, l, r).second;
}
pii res = f[be[l] + 1][be[r] - 1];
res = check(res, Find(l, re[be[l]], l, r));
res = check(res, Find(le[be[r]], r, l, r));
return res.second;
}
void init() {
len = 200;
for (int i = 1; i <= n; ++ i) {
be[i] = (i - 1) / len + 1;
}
for (int i = 1; i <= be[n]; ++ i) {
le[i] = (i - 1) * len + 1, re[i] = i * len;
}
re[be[n]] = n;
for (int i = 1; i <= be[n]; ++ i) {
for (int j = 0; j <= n + 10; ++ j) {
cot[j] = 0;
}
int maxcnt = 0, maxnum = 0;
for (int j = le[i]; j <= n; ++ j) {
cot[val[j]]++;
pii it = check({maxcnt, maxnum}, {cot[val[j]], val[j]});
maxcnt = it.first, maxnum = it.second;
if (be[j] != be[j + 1]) {
f[i][be[j]] = {maxcnt, maxnum};
}
}
}
}
int main() {
n = read<int>(), len = 200;
for (int i = 1; i <= n; ++ i) {
val[i] = read<ll>();
num.emplace_back(val[i]);
}
sort(num.begin(), num.end());
num.erase(unique(num.begin(), num.end()), num.end());
for (int i = 1; i <= n; ++ i) {
val[i] = lower_bound(num.begin(), num.end(), val[i]) - num.begin();
s[val[i]].emplace_back(i);
}
init();
for (int i = 1, l, r; i <= n; ++ i) {
l = read<int>(), r = read<int>();
if (l > r) swap(l, r);
printf("%d\n", num.at(ask(l, r)));
}
return 0;
}