• HDU 4747 Mex【线段树上二分+扫描线】


    【题意概述】

      一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和。

    【题解】

      扫描线+线段树。

      我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到右Mex单调上升。

      然后我们把区间左端点逐渐向右边移动,也就是扫描线是左端点。

      我们可以发现每次移动的影响就是 [这个数的位置, 这个数下一次出现的位置) 这个区间内大于这个数的Mex全部变为这个数。

      那么我们在线段树上二分出第一个大于等于Mex的位置,然后区间修改即可。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define LL long long
     5 #define rg register
     6 #define N 200010
     7 #define ls (u<<1)
     8 #define rs (u<<1|1)
     9 #define mid ((a[u].l+a[u].r)>>1)
    10 using namespace std;
    11 int n,m,v[N],b[N],c[N],nxt[N],pos[N],mex[N];
    12 LL ans,u[N];
    13 struct tree{int l,r,nl,nr; LL sum; bool tag;}a[N<<2];
    14 inline int read(){
    15     int k=0,f=1; char c=getchar();
    16     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    17     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
    18     return k*f;
    19 }
    20 void build(int u,int l,int r){
    21     a[u].l=l; a[u].r=r; a[u].tag=0;
    22     if(l<r){
    23         build(ls,l,mid); build(rs,mid+1,r);
    24         a[u].sum=a[ls].sum+a[rs].sum; a[u].nl=a[ls].nl,a[u].nr=a[rs].nr;
    25     }
    26     else a[u].sum=a[u].nl=a[u].nr=mex[l];
    27 }
    28 inline void pushdown(int u){
    29     a[ls].tag=a[rs].tag=1;
    30     a[ls].nl=a[ls].nr=a[rs].nl=a[rs].nr=a[u].nl;
    31     a[ls].sum=(a[ls].r-a[ls].l+1)*a[ls].nl;
    32     a[rs].sum=(a[rs].r-a[rs].l+1)*a[rs].nl;
    33     a[u].tag=0;    
    34 }
    35 void update(int u,int l,int r,int num){
    36     if(l<=a[u].l&&a[u].r<=r&&a[u].nl>num){
    37         a[u].tag=1; a[u].nl=a[u].nr=num; a[u].sum=(a[u].r-a[u].l+1)*num;
    38         return;
    39     }
    40     if(a[u].nr<=num) return;
    41     if(a[u].tag) pushdown(u);
    42     if(a[ls].nr>num&&l<=mid) update(ls,l,r,num);
    43     if(r>mid) update(rs,l,r,num);
    44     a[u].sum=a[ls].sum+a[rs].sum; a[u].nl=a[ls].nl,a[u].nr=a[rs].nr;
    45 }
    46 LL query(int u,int l,int r){
    47     if(l<=a[u].l&&a[u].r<=r) return a[u].sum;
    48     if(a[u].tag) pushdown(u); LL ret=0;
    49     if(l<=mid) ret+=query(ls,l,r);
    50     if(r>mid) ret+=query(rs,l,r);
    51     return ret;
    52 }
    53 inline void Pre(){
    54     ans=0;
    55     memset(pos,0,sizeof(pos));
    56     memset(u,0,sizeof(u));
    57 }
    58 int main(){
    59     while(1){
    60         n=read(); if(!n) break;
    61         Pre();
    62         for(rg int i=1;i<=n;i++) v[i]=b[i]=read();
    63         sort(b+1,b+1+n); m=unique(b+1,b+1+n)-b-1;
    64         for(rg int i=1;i<=n;i++) c[i]=lower_bound(b+1,b+1+m,v[i])-b;
    65 //        for(rg int i=1;i<=n;i++) printf("%d ",c[i]); puts("c");
    66         for(rg int i=n;i;i--) nxt[i]=(pos[c[i]])?pos[c[i]]:n+1,pos[c[i]]=i;
    67 //        for(rg int i=1;i<=n;i++) printf("%d ",nxt[i]); puts("");
    68         int now=0;
    69         for(rg int i=1;i<=n;i++){
    70             if(v[i]<=n) u[v[i]]=1;
    71             while(u[now]) now++;
    72             ans+=(mex[i]=now);
    73         }
    74 //        for(rg int i=1;i<=n;i++) printf("%d ",mex[i]);
    75 //        printf("ans=%lld
    ",ans);
    76         build(1,1,n);
    77         for(rg int i=1;i<=n;i++){
    78             update(1,i+1,nxt[i]-1,v[i]);
    79             ans+=query(1,i+1,n);
    80 //            printf("ans=%lld
    ",ans);
    81         }
    82         printf("%lld
    ",ans);
    83     }
    84     return 0;
    85 }
  • 相关阅读:
    selenium+python(模块化驱动测试)
    selenium+Python(处理html5的视频播放)
    selenium+Python(文件下载)
    selenium+Python(文件上传)
    selenium+Python(alert 、confirm 、prompt 的处理)
    selenium+Python(表单、多窗口切换)
    Cookie跳转登录验证码
    几种典型的软件自动化测试框架
    Python开发利器之UliPad
    selenium+python(数据驱动测试)
  • 原文地址:https://www.cnblogs.com/DriverLao/p/9823066.html
Copyright © 2020-2023  润新知