主席树求区间没有出现过的最小值
思路:
对于每个数,维护它最后出现的位置。然后维护区间最小值。
查询区间 [ L , R ] [L,R] [L,R]的时候,找到第 R R R颗树.贪心的往左子树走:若左子树的区间最小值 < < < L,就往左走,否则就往右走(右边一定有答案).
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define mid ((l + r) >> 1)
const int maxn = 2e5 + 5;
const int inf = 1e9;
int a[maxn];
int mi[maxn << 5] , ls[maxn << 5] , rs[maxn << 5] , rt[maxn] , tot;
int add (int l , int r , int t , int p , int c)
{
int now = ++tot;
ls[now] = ls[t];
rs[now] = rs[t];
if (l == r) {
mi[now] = c;
return now;
}
if (p <= mid) ls[now] = add (l , mid , ls[now] , p , c);
else rs[now] = add (mid + 1 , r , rs[now] , p , c);
mi[now] = min (mi[ls[now]] , mi[rs[now]]);
return now;
}
int ask (int t , int l , int r , int L)
{
if (l == r) return l;
if (mi[ls[t]] < L) return ask(ls[t] , l , mid , L);
return ask(rs[t] , mid + 1 , r , L);
}
int last[maxn];
int main()
{
int n , m;scanf("%d%d" , &n , &m);
int up = n + 1;
// build(0 , up , rt[0]);
rt[0] = 0;
for (int i = 1 ; i <= n ; i++){
scanf("%d" , a + i);
if ( a[i] > n ) a[i] = n + 1;
rt[i] = add(0 , up , rt[i - 1] , a[i] , i);
}
while(m--){
int l , r;scanf("%d%d" , &l , &r);
printf("%d\n" , ask(rt[r] , 0 , up , l));
}
return 0;
}