[BZOJ 3585] mex

[题目链接]

          https://www.lydsy.com/JudgeOnline/problem.php?id=3585

[算法]

         两种做法 :

         1. 莫队 , 时间复杂度 : O(Nsqrt(N)) (sqrt表示开根号)

         2. 可持久化线段树 , 我们只需在第i棵线段树上维护每个数最晚出现的时间 , 查询时在线段树上二分即可 , 时间复杂度 :O(NlogN)

[代码]

        莫队 :

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200010
const int inf = 2e9;

struct query
{
        int l , r;
        int id;
} q[MAXN];

int n , m , mn = 0;
int a[MAXN] , cnt[MAXN] , ans[MAXN] , belong[MAXN];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline bool cmp(query a , query b)
{
        return belong[a.l] == belong[b.l] ? a.r < b.r : a.l < b.l;        
}
inline void add(int idx)
{
        if (a[idx] >= MAXN) return;
        ++cnt[a[idx]];
        while (cnt[mn] > 0)    ++mn;    
}
inline void dec(int idx)
{
        if (a[idx] >= MAXN) return;
        --cnt[a[idx]];
        if (!cnt[a[idx]]) chkmin(mn , a[idx]);
}

int main()
{
        
        read(n); read(m);
        for (int i = 1; i <= n; i++) read(a[i]);
        for (int i = 1; i <= m; i++)
        {
                read(q[i].l);
                read(q[i].r);        
                q[i].id = i;
        }
        int block = sqrt(n);
        for (int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1;
        sort(q + 1 , q + m + 1 , cmp);
        int l = q[1].l , r = q[1].l - 1;
        for (int i = 1; i <= m; i++)
        {
                while (r < q[i].r)
        {
            add(r + 1);
            r++;
        }
        while (r > q[i].r)
        {
            dec(r);
            r--;
        }
        while (l < q[i].l)
        {
            dec(l);
            l++;
        }
        while (l > q[i].l)
        {
            add(l - 1);
            l--;
        }
                ans[q[i].id] = mn;
        }
        for (int i = 1; i <= m; i++) printf("%d\n" , ans[i]);
        
        return 0;
    
}

               可持久化线段树 :

                

#include<bits/stdc++.h>
using namespace std;
#define N 200010
const int inf = 2e9;

int n , m , idx;
int v[N * 40] , lson[N * 40] , rson[N * 40] , root[N] , a[N];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline void build(int &k , int l , int r)
{
        k = ++idx;
        v[k] = -inf;
        if (l == r) return;
        int mid = (l + r) >> 1;
        build(lson[k] , l , mid);
        build(rson[k] , mid + 1 , r);
}
inline void modify(int &k , int old , int l , int r , int pos , int val)
{
        k = ++idx;
        lson[k] = lson[old] , rson[k] = rson[old];
        v[k] = v[old];
        if (l == r)
        {
                v[k] = val;
                return;
        }        
        int mid = (l + r) >> 1;
        if (mid >= pos) modify(lson[k] , lson[k] , l , mid , pos , val);
        else modify(rson[k] , rson[k] , mid + 1 , r , pos , val);
        v[k] = min(v[lson[k]] , v[rson[k]]);
}
inline int query(int k , int l , int r , int t)
{
        if (l == r) return l;
        int mid = (l + r) >> 1;
        if (v[lson[k]] < t) return query(lson[k] , l , mid , t);
        else return query(rson[k] , mid + 1 , r , t);        
}

int main()
{
        
        read(n); read(m);
        for (int i = 1; i <= n; i++) read(a[i]);
        build(root[0] , 0 , N - 1);
        for (int i = 1; i <= n; i++)
        {
                if (a[i] < N)
                   modify(root[i] , root[i - 1] , 0 , N - 1 , a[i] , i);
                else root[i] = root[i - 1];
        }
        for (int i = 1; i <= m; i++)
        {
                int l , r;
                read(l); read(r);
                printf("%d\n" , query(root[r] , 0 , N - 1 , l));        
        }
        
        return 0;
    
}

 

posted @ 2018-11-17 20:37  evenbao  阅读(214)  评论(1编辑  收藏  举报