离线, 询问排序.
先处理出1~i的答案, 这样可以回答左端点为1的询问.完成后就用seq(1)将1到它下一次出现的位置前更新. 不断这样转移就OK了
--------------------------------------------------------------------
#include<bits/stdc++.h>
using namespace std;
#define M(l, r) (((l) + (r)) >> 1)
const int maxn = 200009;
int id[maxn], N = 0, seq[maxn], n, T[maxn];
bool F[maxn];
struct link {
int pos;
link* next;
} A[maxn], *head[maxn], *pit = A;
struct Q {
int l, r, p;
inline void read(int _p) {
scanf("%d%d", &l, &r); l--; r--;
p = _p;
}
bool operator < (const Q &q) const {
return l < q.l;
}
} B[maxn];
struct Node {
Node *l, *r;
int tag;
Node() {
tag = -1;
l = r = NULL;
}
inline void pushdown() {
if(~tag) {
l->tag = ~l->tag ? min(l->tag, tag) : tag;
r->tag = ~r->tag ? min(r->tag, tag) : tag;
tag = -1;
}
}
} pool[maxn << 1], *pt = pool, *root;
void build(Node* t, int l, int r) {
if(r > l) {
int m = M(l, r);
build(t->l = pt++, l, m);
build(t->r = pt++, m + 1, r);
} else
t->tag = T[l - 1];
}
int L, R, v;
void modify(Node* t, int l, int r) {
if(L <= l && r <= R)
t->tag = ~t->tag ? min(t->tag, v) : v;
else {
t->pushdown();
int m = M(l, r);
if(L <= m) modify(t->l, l, m);
if(m < R) modify(t->r, m + 1, r);
}
}
int query(Node* t, int l, int r) {
if(l == r)
return t->tag;
t->pushdown();
int m = M(l, r);
return L <= m ? query(t->l, l, m) : query(t->r, m + 1, r);
}
int ans[maxn];
int main() {
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
memset(head, 0, sizeof head);
memset(F, false, sizeof F);
int m;
cin >> n >> m;
for(int i = 0; i < n; i++) {
scanf("%d", seq + i);
id[i] = seq[i];
}
sort(id, id + n);
N = unique(id, id + n) - id;
for(int i = 0; i < n; i++)
seq[i] = lower_bound(id, id + N, seq[i]) - id;
for(int i = n - 1; ~i; i--) {
int t = seq[i];
pit->pos = i;
pit->next = head[t];
head[t] = pit++;
}
for(int i = 0; i < n; i++) {
if(id[seq[i]] < maxn) F[id[seq[i]]] = true;
T[i] = i ? T[i - 1] : 0;
while(F[T[i]]) T[i]++;
}
build(root = pt++, 1, n);
for(int i = 0; i < m; i++)
B[i].read(i);
sort(B, B + m);
int p = 0;
for(int i = 0; i < n; i++) {
while(p < m && B[p].l == i) {
L = B[p].r + 1;
ans[B[p].p] = query(root, 1, n);
p++;
}
if(i == n - 1 || p >= m) break;
head[seq[i]] = head[seq[i]]->next;
L = i + 1; R = head[seq[i]] ? head[seq[i]]->pos : n; v = id[seq[i]];
modify(root, 1, n);
}
for(int i = 0; i < m; i++)
printf("%d\n", ans[i]);
return 0;
}
--------------------------------------------------------------------
3585: mex
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 454 Solved: 232
[Submit][Status][Discuss]
Description
有一个长度为n的数组{a1,a2,...,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。
Input
第一行n,m。
第二行为n个数。
从第三行开始,每行一个询问l,r。
Output
一行一个数,表示每个询问的答案。
Sample Input
5 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
2 1 0 2 1
3 3
2 3
2 4
1 2
3 5
Sample Output
1
2
3
0
3
2
3
0
3
HINT
数据规模和约定
对于100%的数据:
1<=n,m<=200000
0<=ai<=109
1<=l<=r<=n
对于30%的数据:
1<=n,m<=1000