1. 程式人生 > >[BZOJ 3585] mex

[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;
    
}