zoukankan      html  css  js  c++  java
  • Mex(线段树的巧妙应用)

    题目要求求某段区间第一个没有出现的数(0,1,2,3.。。。) ,对于所有的区间,我们把这样的数加起来最后得到一个结果。

    首先,我们要求出这样的数,然后还得列举出所有的区间,复杂度太大了。

    换种思路,我们定住L,是不是一次性能求出所有的R所得出的结果,这就用到线段树的性质了,因为在移动L的过程中,移一步只变化一个数,那么就可以用线段树进行维护。

    首先求出[1,R] 以1为左端的所有区间的情况,记录每个点也就是1到那个点的这段区间值sum[i],以这个值建一颗树,那么在L向前移动的时候,每次丢掉一个数a[i-1], 因为少了这一个数,肯定后面有部分区间是变化的,有部分是不变化的,从这点开始向后找第一个与a[i-1]值相等的数的位置p,那么这个位置后面的sum肯定不会变化,因为丢掉的数又补上了。

    那么就可以只考虑,从i位置到p这段里面的sum,如果原先的sum本来就比a[i-1]小,那说明a[i-1]的减少不影响它的值,所以不用改变,而所有大于a[i-1]的值将都变为a[i-1],这样更新一下,求和就可以了。

      1 #include <iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<stdlib.h>
      6 #include<vector>
      7 #include<cmath>
      8 #include<queue>
      9 #include<set>
     10 #include<map>
     11 using namespace std;
     12 //#pragma comment(linker, "/STACK:1024000000,1024000000")
     13 #define N 200010
     14 #define LL __int64
     15 #define INF 0xfffffff
     16 const double eps = 1e-8;
     17 const double pi = acos(-1.0);
     18 const double inf = ~0u>>2;
     19 vector<int>po[N];
     20 map<int,int>f;
     21 LL s[N<<2];
     22 int tm[N<<2];
     23 LL lz[N<<2];
     24 int sum[N];
     25 int p[N],a[N];
     26 bool vis[N];
     27 void up(int w)
     28 {
     29     s[w] = s[w<<1]+s[w<<1|1];
     30     tm[w] = max(tm[w<<1],tm[w<<1|1]);
     31     //cout<<tm[w]<<" "<<w<<endl;
     32 }
     33 void down(int w,int m)
     34 {
     35     if(lz[w]!=-1)
     36     {
     37         tm[w<<1] = tm[w<<1|1] = lz[w];
     38         lz[w<<1] = lz[w<<1|1] = lz[w];
     39         s[w<<1] = lz[w]*(m-m/2);
     40         s[w<<1|1] = lz[w]*(m/2);
     41         lz[w] = -1;
     42         //cout<<lz[w]<<" <"<<w<<endl;
     43     }
     44 }
     45 void build(int l,int r,int w)
     46 {
     47     if(l==r)
     48     {
     49         s[w] = sum[l];
     50         tm[w] = sum[l];
     51         return ;
     52     }
     53     int m = (l+r)>>1;
     54     build(l,m,w<<1);
     55     build(m+1,r,w<<1|1);
     56     up(w);
     57 }
     58 void update(int a,int b,int d,int l,int r,int w)
     59 {
     60     if(a<=l&&b>=r)
     61     {
     62         s[w] = (LL)d*(r-l+1);
     63         tm[w] = d;
     64         lz[w] = d;
     65         //cout<<l<<", "<<r<<" "<<tm[w]<<" "<<d<<endl;
     66         return ;
     67     }
     68     int m = (l+r)>>1;
     69     down(w,r-l+1);
     70     if(a<=m) update(a,b,d,l,m,w<<1);
     71     if(b>m) update(a,b,d,m+1,r,w<<1|1);
     72     up(w);
     73 }
     74 int find(int k,int l,int r,int w)
     75 {
     76     // cout<<s[w]<<" "<<tm[w]<<" "<<l<<" "<<r<<" "<<w<<endl;
     77     if(l==r)
     78     {
     79         //cout<<l<<" "<<tm[w]<<endl;
     80         return l;
     81     }
     82     int m = (l+r)>>1;
     83     down(w,r-l+1);
     84     if(tm[w<<1]>k)
     85         return find(k,l,m,w<<1);
     86     else
     87         return find(k,m+1,r,w<<1|1);
     88 }
     89 LL query(int a,int b,int l,int r,int w)
     90 {
     91     if(a<=l&&b>=r)
     92     {
     93         return s[w];
     94     }
     95     int m = (l+r)>>1;
     96     LL res = 0;
     97     down(w,r-l+1);
     98     if(a<=m)
     99         res+=query(a,b,l,m,w<<1);
    100     if(b>m)
    101         res+=query(a,b,m+1,r,w<<1|1);
    102     return res;
    103 }
    104 int main()
    105 {
    106     int n,i;
    107     while(scanf("%d",&n)&&n)
    108     {
    109         f.clear();
    110         memset(p,0,sizeof(p));
    111         memset(vis,0,sizeof(vis));
    112         memset(lz,-1,sizeof(lz));
    113         for(i = 1; i <= n ; i++)
    114             po[i].clear();
    115         int g = 0;
    116         for(i = 1; i <= n; i++)
    117         {
    118             scanf("%d",&a[i]);
    119             if(!f[a[i]]) f[a[i]] = ++g;
    120             po[f[a[i]]].push_back(i);
    121         }
    122         int o = 0;
    123         for(i = 1; i <= n ; i++)
    124         {
    125             if(a[i]<N)
    126                 vis[a[i]] = 1;
    127             if(a[i]<sum[i-1])
    128                 sum[i] = sum[i-1];
    129             else
    130             {
    131                 while(vis[o])
    132                     o++;
    133                 sum[i] = o;
    134             }
    135         }
    136         LL ans=0;
    137         build(1,n,1);
    138         ans+=s[1];
    139         //cout<<ans<<endl;
    140         p[f[a[1]]] = 1;
    141         for(i = 2; i <= n ; i++)
    142         {
    143             int k;
    144             int mk = f[a[i-1]];
    145             if(p[mk]<po[mk].size())
    146             {
    147                 k = po[mk][p[mk]]-1;
    148                 //cout<<k<<endl;
    149                 //p[mk]++;
    150             }
    151             else k = n;
    152             update(1,i-1,0,1,n,1);
    153             int fk;
    154             if(tm[1]>a[i-1])
    155             {
    156                 fk = find(a[i-1],1,n,1);
    157                     update(fk,k,a[i-1],1,n,1);
    158             }
    159             ans+=query(i,n,1,n,1);
    160            // cout<<ans<<endl;
    161            //cout<<ans<<" "<<fk<<" "<<k<<" "<<a[i-1]<<endl;
    162             //cout<<i<<endl;
    163             //if(a[i]!=a[i-1])
    164             p[f[a[i]]]++;
    165         }
    166         cout<<ans<<endl;
    167     }
    168     return 0;
    169 }
    View Code
  • 相关阅读:
    实验一报告 20135238&20135207
    第十周
    极客Web前端开发资源大荟萃#022
    一个不错的编程小挑战 没事的时候可以试试
    变形金刚的能量方块(含代码)
    Angular控制器之间的数据通信
    使用HTML5本地 Drag和Drop API(native API)
    用requestAnimationFrame优化你的javascript动画
    模板字符串
    ES6的全新特性:模板字符串
  • 原文地址:https://www.cnblogs.com/shangyu/p/3765947.html
Copyright © 2011-2022 走看看