现在的位置: 首页 > 综合 > 正文

hdu 4747 Mex(线段树)

2014年09月29日 ⁄ 综合 ⁄ 共 3218字 ⁄ 字号 评论关闭

Mex

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 1569    Accepted Submission(s): 515


Problem Description
Mex is a function on a set of integers, which is universally used for impartial game theorem. For a non-negative integer set S, mex(S) is defined as the least non-negative integer which is not appeared in S. Now our problem is about mex function on a sequence.

Consider a sequence of non-negative integers {ai}, we define mex(L,R) as the least non-negative integer which is not appeared in the continuous subsequence from aL to aR, inclusive. Now we want to calculate the sum of mex(L,R) for all 1 <= L <= R <= n.

 


Input
The input contains at most 20 test cases.
For each test case, the first line contains one integer n, denoting the length of sequence.
The next line contains n non-integers separated by space, denoting the sequence.
(1 <= n <= 200000, 0 <= ai <= 10^9)
The input ends with n = 0.
 


Output
For each test case, output one line containing a integer denoting the answer.
 


Sample Input
3 0 1 3 5 1 0 2 0 1 0
 


Sample Output
5 24
Hint
For the first test case: mex(1,1)=1, mex(1,2)=2, mex(1,3)=2, mex(2,2)=0, mex(2,3)=0,mex(3,3)=0. 1 + 2 + 2 + 0 +0 +0 = 5.
 


Source

题意:记mex(i,j)为区间i~j内没出现过最小的非负数,题目要求∑∑mex(i,j),即所有mex的值的和

题解:首先处理出所有mex(1,i)的区间,明显这些区间是非递减的,而且很好处理,可以在O(n)时间内处理出来

          然后观察删去最前面的一个数,对所有区间的值的影响

    例如:删去a【1】,若a【1】比所有mex区间的值都要大,那么明显对其他区间都不影响

                如果a【1】在剩下的区间内出现过,那么在下一次a【1】出现前的区间可能会受到影响

               由于区间的mex值是非递减的,那么只要找到第一个区间的mex值大于等于a【1】的,那么a【1】会影响之后的区间,并且这之后的区间的值都会变成a【1】,直到下一个a【1】出现,或者所有区间结束,并且删除a【1】后mex(1,1)的值要置零。那么现在问题就变成了,维护一段区间的和值和最值,和询问非递减序列的比某一个值大的位置,和改变某一段区间的和值。明显,这些操作都可以用线段树维护,所以就用一棵线段树解决该问题。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define lson pos<<1
#define rson pos<<1|1
#define maxn 200008
using namespace std;
int a[maxn],next[maxn];
int mark[maxn],mex[maxn];
struct tree{
    long long sum,mx,lazy;
}sg[maxn*4];
void build(int pos,int l,int r)
{
    int mid=(l+r)>>1;
    if(l==r)
    {
        sg[pos].lazy=-1;
        sg[pos].sum=sg[pos].mx=mex[l];
        return;
    }
    build(lson,l,mid);
    build(rson,mid+1,r);
    sg[pos].lazy=-1;
    sg[pos].mx=max(sg[lson].mx,sg[rson].mx);
    sg[pos].sum=sg[lson].sum+sg[rson].sum;
}
int get(int pos,int l,int r,int val)
{
    int mid=(l+r)>>1;

    if(l==r) return l;
    if(val<sg[lson].mx) return get(lson,l,mid,val);
    return get(rson,mid+1,r,val);
}
void updata(int pos,int l,int r,int ltemp,int rtemp,int val)
{
    int mid=(l+r)>>1;

    if(ltemp<=l&&r<=rtemp)
    {
        sg[pos].lazy=sg[pos].mx=val;
        sg[pos].sum=(r-l+1)*val;
        return;
    }
    if(sg[pos].lazy!=-1)
    {
        sg[lson].lazy=sg[rson].lazy=sg[pos].lazy;
        sg[lson].mx=sg[rson].mx=sg[pos].mx;
        sg[lson].sum=(mid-l+1)*sg[pos].lazy;
        sg[rson].sum=(r-mid)*sg[pos].lazy;
        sg[pos].lazy=-1;
    }
    if(rtemp<=mid) updata(lson,l,mid,ltemp,rtemp,val);
    else if(ltemp>mid) updata(rson,mid+1,r,ltemp,rtemp,val);
    else
    {
        updata(lson,l,mid,ltemp,mid,val);
        updata(rson,mid+1,r,mid+1,rtemp,val);
    }
    sg[pos].sum=sg[lson].sum+sg[rson].sum;
    sg[pos].mx=max(sg[lson].mx,sg[rson].mx);
}
int main()
{
    int n;

    while(scanf("%d",&n)&&n)
    {
        memset(mark,0,sizeof(mark));
        int now=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",a+i);
            next[i]=n+1;
            if(a[i]<=n) mark[a[i]]=1;
            for(;mark[now];now++);
            mex[i]=now;
        }
        memset(mark,0,sizeof(mark));
        for(int i=n;i>=1;i--)
        {
            if(a[i]<=n&&mark[a[i]]) next[i]=mark[a[i]];
            if(a[i]<=n) mark[a[i]]=i;
        }
        build(1,1,n);
        long long res=0;
        for(int i=1;i<=n;i++)
        {
            res+=sg[1].sum;
            if(a[i]<sg[1].mx)
            {
                int ltemp=get(1,1,n,a[i]);
                int rtemp=next[i];
                if(ltemp<rtemp) updata(1,1,n,ltemp,rtemp-1,a[i]);
            }
            updata(1,1,n,i,i,0);
        }
        printf("%I64d\n",res);
    }

    return 0;
}

抱歉!评论已关闭.