[JZOJ4680] 自然数 [HDU4747] Mex

来源:互联网 发布:下列属于软件特性 编辑:程序博客网 时间:2024/05/16 18:37

Description

这里写图片描述
这里写图片描述

Solution

50%

显然,超过N1的数是没有什么用的,所以可以忽略掉。
枚举区间左边界,右边界左边界开始向右扫,维护一个标记数组和答案指针,指针随着标记的更新而增大

O(N2)轻松解决

100%

我们发现,mex(i,i)mex(i,n)是单调不减的
先用50分的方法跑出mex(1,1)mex(1,n)

我们可以从左往右删掉当前第一个数,计算剩余区间的影响和答案
就是说,从mex(1,1)mex(1,n)得出mex(2,2)mex(2,n)

删掉第一个数,造成的影响是一个连续的区间(自己YY),这区间内的mex都赋为这个数

如果得出了区间的左边界和区间的右边界,就可以很简单的用线段树维护。

由于mex的单调性,左边界显然就是第一个mex大于它的位置,这个可以在线段树上二分得到

右边界就是下一个序列中等于它的位置(它后面都不会造成影响),可以预处理

于是在O(NlogN)复杂度内解决

Code

#include<cstdio>#include<cstdlib>#include<cmath>#include<algorithm>#include<cstring>#include<iostream>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)#define N 200005struct node{    long long sm,mx;    int ls,rs;}tr[5*N];using namespace std;int n,a[N],lt[N],b[N],nd;long long lazy[5*N];bool bz[N];long long ans; void down(int now,int l,int mid,int r){    int ls=tr[now].ls,rs=tr[now].rs;    if (lazy[now]!=-1)    {        tr[ls].sm=(mid-l+1)*lazy[now];        tr[rs].sm=(r-mid)*lazy[now];        tr[ls].mx=tr[rs].mx=lazy[now];        lazy[ls]=lazy[rs]=lazy[now];        lazy[now]=-1;    }} void build(int now,int l,int r){    if(l==r) return;    int mid=(l+r)/2;    tr[now].ls=++nd;    build(nd,l,mid);    tr[now].rs=++nd;    build(nd,mid+1,r);}void change(int now,int l,int r,int x,int y,int v){    if (x>y) return;     if (l==x&&r==y)    {        tr[now].sm=v*(r-l+1);        tr[now].mx=v;        lazy[now]=v;        return;    }     int ls=tr[now].ls,rs=tr[now].rs,mid=(l+r)/2;    down(now,l,mid,r);    if(y<=mid) change(ls,l,mid,x,y,v);    else if(x>mid) change(rs,mid+1,r,x,y,v);    else     {        change(ls,l,mid,x,mid,v);        change(rs,mid+1,r,mid+1,y,v);    }    tr[now].sm=tr[ls].sm+tr[rs].sm;    tr[now].mx=max(tr[ls].mx,tr[rs].mx);}int find(int now,int l,int r,int x,int y){    if (l==x&&r==y) return tr[now].sm;    int ls=tr[now].ls,rs=tr[now].rs,mid=(l+r)/2;    long long s;    down(now,l,mid,r);    if (y<=mid) s=find(ls,l,mid,x,y);    else if (x>mid) s=find(rs,mid+1,r,x,y);    else s=find(ls,l,mid,x,mid)+find(rs,mid+1,r,mid+1,y);    return s; } int query(int now,int l,int r,int v){    if (l==r)     {        if (tr[now].mx<=v) return l+2;        return l;    }    int ls=tr[now].ls,rs=tr[now].rs,mid=(l+r)/2;    down(now,l,mid,r);    if (tr[ls].mx>v) return query(ls,l,mid,v);    else return query(rs,mid+1,r,v);}int main(){    cin>>n;    int i,j;    nd=1;    build(1,1,n);    fo(i,1,n)     {        scanf("%d",&a[i]);        if (a[i]>=n) a[i]=n;         b[lt[a[i]]]=i;        lt[a[i]]=i;    }    fo(i,1,n) if (b[i]==0) b[i]=n+1;    int p=0;    ans=0;    memset(lazy,255,sizeof(lazy));    fo(j,1,n)    {        bz[a[j]]=1;        while (bz[p]==1) p++;        ans+=p;        change(1,1,n,j,j,p);    }    fo(j,1,n-1)    {        int lp=query(1,1,n,a[j]),rp=b[j];        change(1,1,n,lp,rp-1,a[j]);        ans+=find(1,1,n,j+1,n);    }     cout<<ans;}
0 0
原创粉丝点击