zoukankan      html  css  js  c++  java
  • hdu 4747【线段树-成段更新】.cpp

    题意:

      给出一个有n个数的数列,并定义mex(l, r)表示数列中第l个元素到第r个元素中第一个没有出现的最小非负整数。

      求出这个数列中所有mex的值。

      

    思路:

      可以看出对于一个数列,mex(r, r~l)是一个递增序列

      mex(0, 0~n-1)是很好求的,只需要遍历找出第一个没有出现的最小非负整数就好了。这里有一个小技巧:

    1 tmp = 0;
    2 for (int i = 1; i <= n; ++i) {
    3             mp[arr[i]] = 1;
    4             while (mp.find(tmp) != mp.end()) tmp++;
    5             mex[i] = tmp;
    6 }
    View Code

      这样可以利用map中的红黑树很快找到第一个没有出现的最小非负整数。

      然后在求mex(1~n-1, 0~n-1)的过程中,我们可以看出,每消除当前值arr[i],会影响到的是在下一个arr[i]出现前 往后的mex值中比arr[i]大的值,即如果当前这个值不存在了,那么在这个值下一次出现前,mex值比当前值大的mex值都应被替换成arr[i]。

      所以我们可以再一次利用map的红黑树找到当前值下一次出现的位置,然后利用线段树成段更新往后的mex值和求出会影响到的mex值的个数。

    1 for (int i = n; i >= 1; --i) {
    2             if (mp.find(arr[i]) == mp.end()) next[i] = n+1;
    3             else next[i] = mp[arr[i]];
    4             mp[arr[i]] = i;
    5 }
    View Code

        这里我们还需要利用线段树求出第一个比当前arr[i]大的mex值的位置,以便成段更新区间的mex值。

    Tips:

    ※ 这里有一个小小优化的地方,就是当更新的时候,可以先查看mx[1]是否比当前值大,如果是,则表示往后的区间里有比当前值大的mex值,则需要线段树是需要更新的,否则不用更新。

    ※ 还有一个要注意的地方是:只有求出的左边界比右边界小的时候才能更新。

    Code:

      1 #include <stdio.h>
      2 #include <cstring>
      3 #include <map>
      4 #include <algorithm>
      5 using namespace std;
      6 
      7 const int MAXN = 200010;
      8 long long sum[MAXN<<2];
      9 int mx[MAXN<<2], arr[MAXN], next[MAXN], mex[MAXN];
     10 int lazy[MAXN<<2];
     11 
     12 void Pushup(int rt)
     13 {
     14     sum[rt] = sum[rt<<1]+sum[rt<<1|1];
     15     mx[rt] = max(mx[rt<<1], mx[rt<<1|1]);
     16 }
     17 
     18 void Pushdown(int rt, int x)
     19 {
     20     if (lazy[rt] != -1) {
     21         lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
     22         sum[rt<<1] = (x-x/2)*lazy[rt];
     23         sum[rt<<1|1] = x/2*lazy[rt];
     24         mx[rt<<1] = mx[rt<<1|1] = lazy[rt];
     25         lazy[rt] = -1;
     26     }
     27 }
     28 
     29 void Creat(int l, int r, int rt)
     30 {
     31     lazy[rt] = -1;
     32     if (l == r) {
     33         sum[rt] = mx[rt] = mex[l];
     34         return;
     35     }
     36     int mid = (l+r)/2;
     37     Creat(l, mid, rt<<1);
     38     Creat(mid+1, r, rt<<1|1);
     39     Pushup(rt);
     40 }
     41 
     42 void Modify(int l, int r, int x, int L, int R, int rt)
     43 {
     44     if (l <= L && r >= R) {
     45         lazy[rt] = x;
     46         sum[rt] = x*(R-L+1);
     47         mx[rt] = x;
     48         return;
     49     }
     50     Pushdown(rt, R-L+1);
     51     int mid = (L+R)/2;
     52     if (l <= mid) Modify(l, r, x, L, mid, rt<<1);
     53     if (r > mid) Modify(l, r, x, mid+1, R, rt<<1|1);
     54     Pushup(rt);
     55 }
     56 
     57 int Get(int rt, int l, int r, int x)
     58 {
     59     if(l == r) return l;
     60     Pushdown(rt, r-l+1);
     61     int mid = (l+r)/2;
     62     if (mx[rt<<1] > x) return Get(rt<<1, l, mid, x);
     63     else return Get(rt<<1|1, mid+1, r, x);
     64 }
     65 
     66 int main()
     67 {
     68     //freopen("in.txt", "r", stdin);
     69     int n, tmp;
     70     long long ans_sum;
     71     map<int, int> mp;
     72     while (~scanf("%d", &n)) {
     73         if (n == 0) break;
     74         ans_sum = tmp = 0;
     75         mp.clear();
     76         memset(sum, 0, sizeof(sum));
     77         memset(next, 0, sizeof(next));
     78 
     79         for (int i = 1; i <= n; ++i)
     80             scanf("%d", &arr[i]);
     81         for (int i = 1; i <= n; ++i) {
     82             mp[arr[i]] = 1;
     83             while (mp.find(tmp) != mp.end()) tmp++;
     84             mex[i] = tmp;
     85         }
     86 
     87         Creat(1, n, 1);
     88         mp.clear();
     89         for (int i = n; i >= 1; --i) {
     90             if (mp.find(arr[i]) == mp.end()) next[i] = n+1;
     91             else next[i] = mp[arr[i]];
     92             mp[arr[i]] = i;
     93         }
     94 
     95         for (int i = 1; i <= n; ++i) {
     96             ans_sum += sum[1];
     97             if (mx[1] > arr[i]) {
     98                 int l = Get(1, 1, n, arr[i]);
     99                 int r = next[i];
    100        // printf("%d %d %d
    ", l, r, sum[1]);
    101                 if (l < r) Modify(l, r-1, arr[i], 1, n, 1);
    102             }
    103 
    104             Modify(i, i, 0, 1, n, 1);
    105         }
    106         printf("%I64d
    ", ans_sum);
    107     }
    108     return 0;
    109 }
    View Code

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

  • 相关阅读:
    DWR2.0的DefaultContainer can't find a classes异常的解决方案
    IIS7.5(FastCGI)PHP7安装手记
    android手机一句话备忘录
    设计模式学习每日一记(21.叠代器模式)
    设计模式学习每日一记(20.中介者模式)
    C&C++多系统集成需要注意的问题
    设计模式学习每日一记(23.责任链模式)
    设计模式学习每日一记(22.访问者模式)
    源码阅读工具总结
    zte v880刷机入门篇
  • 原文地址:https://www.cnblogs.com/Griselda/p/3433595.html
Copyright © 2011-2022 走看看