hdu 4747 Mex —— 线段树+思维

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
2013 ACM/ICPC Asia Regional Hangzhou Online

想不到怎么都想不出来,还是看了题解才知道的,先O(n)处理一在次1开头的情况,然后i往后移的时候,更新a[i]与下一个a[i]之间的值,下一个a[i]之后就没有影响了。因为去掉了a[i],所以比a[i]大的值更新为a[i],每次update之后答案就是sum[root]。
要在build的时候更新sum,flag,maxn的值,我都忘了是要乘4倍的,wa了好几次QAQ

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
const int inf=1e9+5;
ll mex[200005*4],sum[200005*4],flag[200005*4],maxn[200005*4];
void pushup(int root)
{
    sum[root]=sum[root<<1]+sum[root<<1|1];
    maxn[root]=max(maxn[root<<1],maxn[root<<1|1]);
}
void pushdown(int l,int r,int root)
{
    int mid=l+r>>1;
    if(flag[root]==-1)
        return ;
    sum[root<<1]=(ll)(mid-l+1)*flag[root];
    sum[root<<1|1]=(ll)(r-mid)*flag[root];
    flag[root<<1]=flag[root<<1|1]=flag[root];
    maxn[root<<1]=maxn[root<<1|1]=flag[root];
    flag[root]=-1;
}
void build(int l,int r,int root)
{
    maxn[root]=sum[root]=0;
    flag[root]=-1;
    if(l==r)
    {
        maxn[root]=sum[root]=mex[l];
        return ;
    }
    int mid=l+r>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    pushup(root);
}
void update(int l,int r,int root,int ql,int qr,int val)
{
    if(l>=ql&&r<=qr)
    {
        sum[root]=(ll)(r-l+1)*val;
        flag[root]=maxn[root]=(ll)val;
        return ;
    }
    pushdown(l,r,root);
    int mid=l+r>>1;
    if(mid>=ql)
        update(l,mid,root<<1,ql,qr,val);
    if(mid<qr)
        update(mid+1,r,root<<1|1,ql,qr,val);
    pushup(root);
}
int query(int l,int r,int root,int val)
{
    if(val>maxn[root])
        return inf;
    if(l==r)
        return l;
    int mid=l+r>>1;
    int ans=query(l,mid,root<<1,val);
    if(ans>=inf)
        ans=query(mid+1,r,root<<1|1,val);
    return ans;
}
vector<int>vec[200005];
int vis[200005],cnt[200005],a[200005];
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        for(int i=0;i<200005;i++)
        {
            vis[i]=cnt[i]=0;
            vec[i].clear();
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]>n)
                a[i]=n+1;
            vec[a[i]].push_back(i);
        }
        int pos=0;
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            vis[a[i]]=1;
            while(vis[pos])
                pos++;
            mex[i]=pos;
            ans+=mex[i];
        }
        build(1,n,1);
        for(int i=1;i<=n;i++)
        {
            cnt[a[i]]++;
            int fin;
            if(cnt[a[i]]<vec[a[i]].size())
                fin=vec[a[i]][cnt[a[i]]]-1;
            else
                fin=n;
            int sta=query(1,n,1,a[i]);
            if(sta<=fin)
                update(1,n,1,sta,fin,a[i]);
            ans+=sum[1];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/82026557
Mex