• hdu 4747 mex 线段树+思维


    http://acm.hdu.edu.cn/showproblem.php?pid=4747

    题意:

    我们定义mex(l,r)表示一个序列a[l]....a[r]中没有出现过得最小的非负整数, 然后我们给出一个长度为n的序列,求他所有的连续的子序列的mex(l,r)的和。

    思路:

    首先因为n的最大值就是2*10^5 所有我们字需要考虑200000之内的数就好了,然后O(2*n)可以求出(1,1),(1,2), (1,3),(1,4) ... (1,n)来 mex是不减的。

    然后我们考虑将第一个数拿走我们就能够得到(2,2),(2,3) ......(2,n) , 如何求他们?下边给出图解:

    下边是粘贴别人的,感觉有个例子很好理解。

    例:           1, 6,0,2,3,1,4,3

    初始mex 0, 02,3,44,5,5        mex[1,r]

    删除1后   0,  01,1,14,5,5         mex[2,r]

    ……

    当删除第一个1后,红色的mex不变!,紫色的mex值变为1橙色的mex值不变,删除点的mex置0

    因此,用线段树维护一个单调不递增队列,每次求和。查找位置时用二分。线段树延时标记即可。

    ps:我这里二笔了一下,题意一下大家,lazy一定要出事化为-1,因为这里面有置0的操作。我因此wa好多次。。

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <functional>
    #include <numeric>
    #include <sstream>
    #include <stack>
    #include <map>
    #include <queue>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    
    #define lc l,m,rt<<1
    #define rc m + 1,r,rt<<1|1
    #define pi acos(-1.0)
    #define ll __int64
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   (x) < (y) ? (x) : (y)
    #define Max(x, y)   (x) < (y) ? (y) : (x)
    #define E(x)        (1 << (x))
    #define iabs(x)     (x) < 0 ? -(x) : (x)
    #define OUT(x)  printf("%I64d
    ", x)
    #define keyTree (chd[chd[root][1]][0])
    #define Read()  freopen("din.txt", "r", stdin)
    #define Write() freopen("dout.txt", "w", stdout);
    
    
    #define M 100007
    #define N 200017
    
    using namespace std;
    
    int dx[4]={-1,1,0,0};
    int dy[4]={0,0,-1,1};
    
    const int inf = 0x7f7f7f7f;
    const int mod = 1000000007;
    
    const double eps = 1e-8;
    
    int mex[N],a[N],next[N];
    int vis[N];
    ll val[4*N], lz[4*N];
    int n;
    
    void pushup(int rt)
    {
        val[rt] = val[rt<<1] + val[rt<<1|1];
    }
    void pushdown(int rt,int m)
    {
        if (lz[rt] != -1)
        {
            lz[rt<<1] = lz[rt<<1|1] = lz[rt];
            val[rt<<1] = lz[rt] * (m - (m>>1));
            val[rt<<1|1] = lz[rt] * (m>>1);
            lz[rt] = -1;
        }
    }
    void build(int l, int r, int rt)
    {
        lz[rt] = -1;
        val[rt] = 0;
        if (l == r)
        {
            val[rt] = mex[l];
            return ;
        }
        int m = (l + r) >> 1;
        build(lc);  build(rc);
        pushup(rt);
    }
    void update(int L, int R, ll sc, int l, int r, int rt)
    {
        if (l >= L && r <= R)
        {
            lz[rt] = sc;
            val[rt] = sc*(r - l + 1);
            return ;
        }
        pushdown(rt,r - l + 1);
        int m = (l + r) >> 1;
        if (L <= m) update(L,R,sc,lc);
        if (R > m) update(L,R,sc,rc);
        pushup(rt);
    }
    ll query(int pos, int l,int r, int rt)
    {
        if (l == r) return val[rt];
        int m = (l + r) >> 1;
        pushdown(rt, r - l + 1);
        if (pos <= m) return query(pos,lc);
        else return query(pos,rc);
    }
    int BSR(int l, int r, int v)
    {
        int ans = -1;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            if (query(mid,1,n,1) > v)
            {
                ans = mid;
                r = mid - 1;
            } else l = mid + 1;
        }
        return ans;
    }
    int main()
    {
        while (~scanf("%d",&n))
        {
            if (!n) break;
            CL(vis,0); CL(next,0);
            for (int i = 1; i <= n; ++i)
            {
                scanf("%d",&a[i]);
                a[i] = min(a[i],200001);
                if (vis[a[i]]) next[vis[a[i]]] = i;
                vis[a[i]] = i;
            }
            for (int i = 1; i <= n; ++i) if (!next[i]) next[i] = n + 1;
            CL(vis,0);  int last = 0;
            for (int i = 1; i <= n; ++i)
            {
                vis[a[i]] = 1;
                while (true)
                {
                    if (!vis[last])
                    {
                        mex[i] = last;
                        break;
                    }
                    last++;
                }
            }
            build(1,n,1); ll ans = 0;
            for (int i = 1; i <= n; ++i)
            {
                ans += val[1];
                if (i == n) continue;
                int l = i + 1;
                int r = next[i] - 1;
                int pos = BSR(l,r,a[i]);
                if (pos != -1) update(pos, r, a[i], 1, n, 1);
                update(i, i, 0, 1, n, 1);
            }
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    c++ 输出 变量名 字符串(zz.is2120.BG57IV3)
    分页存储过程
    连接字符串
    动软 DBHeper 完全代码
    java 数据库连接字符串
    DOS命令行下常见的错误信息
    点击单元格选择整行,又可编辑单元格
    label里文字中的下划线
    Delphi程序中动态生成控件的方法及应用
    双击dbgrid排序的问题
  • 原文地址:https://www.cnblogs.com/E-star/p/3348552.html
Copyright © 2020-2023  润新知