【CF-1436E】Complicated Computations(贪心+主席数求区间MEX)

题目链接:https://codeforces.ml/contest/1436/problem/E

题目大意

给定一个序列,每次枚举一对 (l,r),能够得到 (MEX),对于整个序列的所有的 (l,r),求其所有的 (MEX) 数的 (MEX)

花絮

之前和WISH2LUCKY讨论了一个鬼畜的MEX问题,然后就让他做了区间MEX的模板题,然后7酱路过,就说起了这题。

做这题之前补了牛客小米邀请赛第一场的E,也就拓宽了一些思路qwq。

思路

已知相同的一个数能将一个序列划分成不同的好几段,假定这个数是答案,例如一个数为 (1),序列为 ({2,1,3,4,1,4,6,7,1,3}),那么划分后能得到 ({2},{3,4},{4,6,7},{3})。如果这个数是不是答案,那么会是这些段的 (MEX)。如果对于所有裁剪出来的,都不是 (MEX),从小到大枚举,那就是答案了!

那么如何证明是裁剪出来的一整段呢?这部分是口胡出来的,证明本当苦手

因为如果是较小的数的话,会将裁剪后的进行进一步切分,所以 出现的 (MEX) 只会变小,因为枚举的数以及不在裁剪后的部分里面了,所以 (MEX) 只会更小,而更小的情况在枚举的时候就能判断掉了。

AC代码

板子很长,跑得挺快

#include <bits/stdc++.h>

#define SZ(x) (int)x.size()
using namespace std;
const int MAXN = 1e5 + 5;

int bep;

class HJT {
public:
    struct node {
        int lson, rson, maxx;
    } T[MAXN * 70];
    int tol;
#define ls T[rt].lson
#define rs T[rt].rson

    inline void push_up(int rt) {
        T[rt].maxx = max(T[ls].maxx, T[rs].maxx);
    }

    int build(int l, int r) {
        int nrt = ++tol;
        int mid = (l + r) >> 1;
        T[nrt].lson = T[nrt].rson = 0;
        T[nrt].maxx = bep;
        if (l < r) {
            T[nrt].lson = build(l, mid);
            T[nrt].rson = build(mid + 1, r);
            push_up(nrt);
        }
        return nrt;
    }

    int update(int rt, int pos, int v, int be, int en) {
        int nrt = ++tol;
        if (be == en) {
            T[nrt].maxx = v;
            return nrt;
        }
        int mid = (be + en) >> 1;
        if (pos <= mid) {
            T[nrt].lson = update(T[rt].lson, pos, v, be, mid);
            T[nrt].rson = T[rt].rson;
        } else {
            T[nrt].lson = T[rt].lson;
            T[nrt].rson = update(T[rt].rson, pos, v, mid + 1, en);
        }
        push_up(nrt);
        return nrt;
    }

    int query(int rt, int R, int be, int en) {
        if (be == en) return be;
        int ans = -1;
        int mid = (be + en) >> 1;
        if (T[ls].maxx > R) ans = query(T[rt].lson, R, be, mid);
        if (ans == -1 && T[rs].maxx > R) ans = query(T[rt].rson, R, mid + 1, en);
        return ans;
    }
} tree;

int root[MAXN];
int a[MAXN];

vector<int> vec[MAXN];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    bep = n + 1;
    root[n + 1] = tree.build(1, n+1);
    for (int i = n; i >= 1; i--) {
        int x = a[i];
        root[i] = tree.update(root[i + 1], x, i, 1, n+1);
    }

    for (int i = 1; i <= n; i++) {
        vec[a[i]].push_back(i);
    }

    for (int i = 1; i <= n+1; i++) {
        int flag = 0;
        if (SZ(vec[i]) == 0) {
            printf("%d", i+1);
            return 0;
        }
        for (int j = 0; j <= SZ(vec[i]); j++) {
            int l, r;
            if (j == 0) {
                l = 1, r = vec[i][j] - 1;
            } else if (j == SZ(vec[i])) {
                l = vec[i][j - 1] + 1, r = n;
            } else {
                l = vec[i][j - 1] + 1, r = vec[i][j] - 1;
            }
            if (l > r) continue;
            else {
                int tmp = tree.query(root[l], r, 1, n+1);
                if (tmp == -1) continue;
                else {
                    if (tmp == i) {
                        flag = 1;
                    }
                }
            }
        }
        if (!flag) {
            printf("%d
", i);
            return 0;
        }
    }
}
原文地址:https://www.cnblogs.com/tudouuuuu/p/14010275.html