题意: 给定
n
n
n个数,
q
q
q次查询,每次查询给出
[
l
,
r
]
[l,r]
[l,r],查询这个区间内只出现一次的数。
思路: 用
p
r
e
pre
pre数组记录每个数在数组前一次出现的位置,初始化为0,只要在
[
l
,
r
]
[l,r]
[l,r]内出现的数的
p
r
e
[
a
[
i
]
]
<
l
pre[a[i]]<l
pre[a[i]]<l就是有解的。所以可以用主席树维护最小值和当前位置,当
p
r
e
[
a
[
i
]
]
=
0
pre[a[i]]=0
pre[a[i]]=0时,向主席树第
i
i
i个点插入0,否则,先把第
p
r
e
[
a
[
i
]
]
pre[a[i]]
pre[a[i]]置为
I
N
F
INF
INF,然后把第
i
i
i个位置的数置为
p
r
e
[
a
[
i
]
]
pre[a[i]]
pre[a[i]],这样消除了前面的影响。查询时就查询第
r
o
o
t
[
r
]
root[r]
root[r]棵线段树内查询区间
[
l
,
r
]
[l,r]
[l,r]内的
p
r
e
[
a
[
i
]
]
pre[a[i]]
pre[a[i]]的最小值,若最小值小于
l
l
l则有解,否则输出0。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
#define P pair<int,int>
using namespace std;
const int N = 5e5 + 10;
int n, q, a[N], p[N], root[N], cnt;
struct node {
int l, r, id, pre;
} zxs[N * 40];
void ins(int l, int r, int pre, int &now, int pos, int qian) {
zxs[++cnt] = zxs[pre], now = cnt;
if(l == r) {
zxs[now].id = l;
zxs[now].pre = qian;
return;
}
int m = l + r >> 1;
if(pos <= m)
ins(l, m, zxs[pre].l, zxs[now].l, pos, qian);
else
ins(m + 1, r, zxs[pre].r, zxs[now].r, pos, qian);
if(zxs[zxs[now].l].pre < zxs[zxs[now].r].pre)
zxs[now].pre = zxs[zxs[now].l].pre, zxs[now].id = zxs[zxs[now].l].id;
else
zxs[now].pre = zxs[zxs[now].r].pre, zxs[now].id = zxs[zxs[now].r].id;
}
P query(int l, int r, int x, int y, int w) {
if(l == x && r == y) {
P p = make_pair(zxs[w].pre, zxs[w].id);
return p;
}
int m = x + y >> 1;
if(r <= m)
return query(l, r, x, m, zxs[w].l);
else if(l > m)
return query(l, r, m + 1, y, zxs[w].r);
else
return min(query(l, m, x, m, zxs[w].l), query(m + 1, r, m + 1, y, zxs[w].r));
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if(p[a[i]] == 0)
ins(1, n, root[i - 1], root[i], i, 0);
else {
int t;
ins(1, n, root[i - 1], t, p[a[i]], INF);
ins(1, n, t, root[i], i, p[a[i]]);
}
p[a[i]] = i;
}
scanf("%d", &q);
for(int x, y, i = 0; i < q; i++) {
scanf("%d%d", &x, &y);
P ans = query(x, y, 1, n, root[y]);
if(ans.first < x)
printf("%d\n", a[ans.second]);
else
puts("0");
}
return 0;
}