主席树求Mex:P4137

主席树求区间没有出现过的最小值

思路:

对于每个数,维护它最后出现的位置。然后维护区间最小值。

查询区间 [ 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;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/109023309