zoukankan      html  css  js  c++  java
  • @bzoj


    @description@

    Input

    Output

    Sample Input
    7 5
    0 2 1 0 1 3 2
    1 3
    2 3
    1 4
    3 6
    2 7
    Sample Output
    3
    0
    3
    2
    4

    Hint

    @solution@

    在线不大好搞,因为 mex 函数不大支持合并,也没有比较好用的性质。
    离线,如果采用每次加入一个数的方法也不大好搞。

    但是反过来,假如我现在的区间的 mex 是 ans,删掉一个 a[x] 后如果剩下的区间没有与 a[x] 相同的数,可以得到新的 ans' = min(ans, a[x])。
    这个证明还是比较直观的。也就是说我们可以写莫队了。我们接下来的算法就利用这个性质。

    考虑固定左端点 l,维护以 l~n 中的下标作为右端点的 mex 值。记录 nxt[l] 表示 l 之后最近的与 a[l] 相同的位置。
    每次从 l 转移到 l + 1 时就直接对区间 [l, nxt[l] - 1] 进行区间对 a[l] 取 min 的操作即可。
    因为 mex 值是单调的(越远越大),这个很容易就线段树维护出来了。查询直接离线在线段树上查就可以了。
    也许可以强制在线然后用可持久化线段树搞。

    @accepted code@

    #include<cstdio>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int MAXN = 200000;
    vector<pair<int, int> >vec[MAXN + 5];
    int n, m, a[MAXN + 5], ans[MAXN + 5];
    int mex[MAXN + 5];
    struct segtree{
        struct node{
            int l, r, mtag;
        }t[4*MAXN + 5];
        void build(int x, int l, int r) {
            t[x].l = l, t[x].r = r, t[x].mtag = MAXN;
            if( l == r ) return ;
            int mid = (l + r) >> 1;
            build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
        }
        void modify(int x, int l, int r, int k) {
            if( l > t[x].r || r < t[x].l )
                return ;
            if( l <= t[x].l && t[x].r <= r ) {
                t[x].mtag = min(t[x].mtag, k);
                return ;
            }
            modify(x << 1, l, r, k), modify(x << 1 | 1, l, r, k);
        }
        int query(int x, int p) {
            if( t[x].l == t[x].r ) return min(t[x].mtag, mex[p]);
            int mid = (t[x].l + t[x].r) >> 1;
            if( p <= mid ) return min(t[x].mtag, query(x << 1, p));
            else return min(t[x].mtag, query(x << 1 | 1, p));
        }
    }T;
    bool tag[MAXN + 5];
    int nxt[MAXN + 5], adj[MAXN + 5];
    void solve() {
        int pos = 0;
        for(int i=1;i<=n;i++) {
            tag[a[i]] = true;
            while( tag[pos] ) pos++;
            mex[i] = pos;
        }
        for(int i=n;i>=1;i--) {
            nxt[i] = (adj[a[i]] ? adj[a[i]] : n + 1);
            adj[a[i]] = i;
        }
        T.build(1, 1, n);
        for(int i=1;i<=n;i++) {
            for(int j=0;j<vec[i].size();j++)
                ans[vec[i][j].second] = T.query(1, vec[i][j].first);
            T.modify(1, 1, nxt[i]-1, a[i]);
        }
    }
    int main() {
        scanf("%d%d", &n, &m);
        for(int i=1;i<=n;i++)
            scanf("%d", &a[i]);
        for(int i=1;i<=m;i++) {
            int L, R; scanf("%d%d", &L, &R);
            vec[L].push_back(make_pair(R, i));
        }
        solve();
        for(int i=1;i<=m;i++)
            printf("%d
    ", ans[i]);
    }
    

    @details@

    不得不说,通过删除一个数来维护新的区间信息的题目还是比较少见的。因为大多数题目都是维护加入一个数的情况。

    人类智慧。

  • 相关阅读:
    PHP中使用CURL实现GET和POST请求
    ecstore关于smarty语法调用
    Linux 定时任务详解
    fzu 1753 Another Easy Problem
    zoj 2562 More Divisors
    poj 2992 Divisors
    UVA10078多边形判断凹凸性
    UVA10002求凸包的质心
    UVA10088多边形内整点个数计算(计算几何)
    HDU 1824 简单2-sat
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11304182.html
Copyright © 2011-2022 走看看