HDU 4747 Mex

来源:互联网 发布:乐外卖是什么软件 编辑:程序博客网 时间:2024/06/08 02:31

题意:

给出一段数字a  定义mex(l,r)表示a[l]...a[r]中最小的不连续的数字  求出所有mex(l,r)的和


思路:

首先可以想到由l开始到n的所有数字的mex值必然是递增的  那么就可以求出以1开始到n的所有数字的mex  从前到后扫一遍即可  这时可以求出[1,r]所有区间的mex和  利用线段树即可

接着考虑如何求[2,r]、[3,r]....  由[1,r]到[2,r]的转变无非是去掉第一个数字  那么去掉一个数字的影响是什么呢?

比如去掉一个2  那他最多影响到下一个2出现的地方  而且  他只是把mex>2的地方改成了2  即从2处截断  又因为之前所说的递增关系  所以影响的区间也一定是连续的!

那么我们就可以每次删掉一个数字  利用线段树找出他影响的区间  并把这个区间覆盖为那个删掉的数字

最后每次求和就是答案


代码:

#include<cstdio>#include<cstring>#include<algorithm>#include<map>using namespace std;typedef __int64 ll;#define N 201000#define L(x) (x<<1)#define R(x) ((x<<1)|1)struct node{    int l,r,val,lazy;    ll sum;}tree[N*4];int a[N],mex[N],next[N];int n,l,r;map<int,int> mp;ll ans;void up(int i){    tree[i].val=max(tree[L(i)].val,tree[R(i)].val);    tree[i].sum=tree[L(i)].sum+tree[R(i)].sum;}void down(int i){    if(tree[i].lazy!=-1)    {        tree[L(i)].lazy=tree[i].lazy;        tree[L(i)].val=tree[i].lazy;        tree[L(i)].sum=(tree[L(i)].r-tree[L(i)].l+1)*tree[i].lazy;        tree[R(i)].lazy=tree[i].lazy;        tree[R(i)].val=tree[i].lazy;        tree[R(i)].sum=(tree[R(i)].r-tree[R(i)].l+1)*tree[i].lazy;        tree[i].lazy=-1;    }}void init(int l,int r,int i){    tree[i].l=l; tree[i].r=r; tree[i].lazy=-1;    if(l==r)    {        tree[i].val=mex[l];        tree[i].sum=mex[l];        return ;    }    int mid=(l+r)>>1;    init(l,mid,L(i));    init(mid+1,r,R(i));    up(i);}void update(int l,int r,int i,int k){    if(l==tree[i].l&&r==tree[i].r)    {        tree[i].sum=(tree[i].r-tree[i].l+1)*k;        tree[i].val=k;        tree[i].lazy=k;        return ;    }    down(i);    int mid=(tree[i].l+tree[i].r)>>1;    if(r<=mid) update(l,r,L(i),k);    else if(l>mid) update(l,r,R(i),k);    else    {        update(l,mid,L(i),k);        update(mid+1,r,R(i),k);    }    up(i);}void query(int i,int k){    if(tree[i].l==tree[i].r)    {        if(tree[i].val>k) l=tree[i].l;        else l=n+1;        return ;    }    down(i);    if(tree[L(i)].val>k) query(L(i),k);    else query(R(i),k);    up(i);}int main(){    int i,j;    while(~scanf("%d",&n))    {        if(!n) break;        mp.clear(); // get mex        j=0;        for(i=1;i<=n;i++)        {            scanf("%d",&a[i]);            mp[a[i]]=1;            while(mp[j]) j++;            mex[i]=j;        }        mp.clear(); // get next        for(i=1;i<=n;i++) mp[a[i]]=n+1;        for(i=n;i>=1;i--)        {            next[i]=mp[a[i]];            mp[a[i]]=i;        }        //for(i=1;i<=n;i++) printf("%d %d\n",mex[i],next[i]);        init(1,n,1);        for(i=1,ans=0;i<=n;i++)        {            ans+=tree[1].sum;            query(1,a[i]);            r=next[i];            //printf("%d %d\n",l,r);            if(l<r)            {                update(l,r-1,1,a[i]);            }            update(i,i,1,0);        }        printf("%I64d\n",ans);    }    return 0;}


0 0
原创粉丝点击