HDU 4747 Mex(线段树维护mex)经典

 

Mex

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


 

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

 

 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6373 6372 6371 6370 6369 

 

#include
#include
#include
#include//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0};
#include//ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
#include
#include
#include
#include
#include
#include
#define mod 1e9+7
#define ll unsigned long long
#define MAX 1000000000
#define ms memset
#define maxn 200005
#define lr ll l,ll r,ll rt
using namespace std;

ll n,seq[maxn];
ll mex[maxn],pre[maxn];

ll tree[maxn<<2],maxv[maxn<<2];
ll lazy[maxn<<2];
map mp;
/*

题目大意:给定一个序列,要求所有连续子区间的mex值之和。

观察mex函数,
令f1=mex(1,1)+mex(1,2)+...mex(1,n);
可以看到mex(1,i)关于i是递增的。
那么我们不妨找fi与f(i+1)的关系,
即去除了ai元素对后面的前缀和有何影响。

对于mex值大于ai的元素,显然无影响,
唯一的影响是i位置到ai元素下一个出现位置之间的和,
即用线段树维护初始序列mex(1,1),mex(1,2),,,mex(1,n)。
然后不断删除ai后,二分查找mex值为大于等于ai的第一个位置,
然后右边区间是ai元素下一个出现的位置,这两个位置之间的mex值(mex(j,n))均更新为ai。

维护下区间和和最大值即可。

这题代码不知道为什么过不了。。。。
整体思路大致是如此。
很是纠结,希望大神指点。

*/

void pushup(ll rt,ll l,ll r)
{
    if(l==r) return;
    tree[rt]=tree[rt<<1]  +  tree[rt<<1|1];
    maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
}

void pushdown(ll rt,ll l,ll r)
{
    ll mid=(l+r)>>1;
    if(lazy[rt])
    {
        tree[rt<<1]=(ll)(mid-l+1)*tree[rt];
        tree[rt<<1|1]=(ll)(r-mid)*tree[rt];
        maxv[rt<<1]=maxv[rt];
        maxv[rt<<1|1]=maxv[rt];
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        lazy[rt]=0;
    }
}

void Build(ll l,ll r,ll rt)
{
    lazy[rt]=0;
    if(l==r)
    {
        tree[rt]=mex[l];
        maxv[rt]=mex[l];
        return ;
    }
    ll mid=(l+r)>>1;
    Build(l,mid,rt<<1);
    Build(mid+1,r,rt<<1|1);
    pushup(rt,l,r);
}

void update(ll l,ll r,ll rt,ll L,ll R,ll d)
{
    if(L<=l&&r<=R)
    {
        maxv[rt]=(ll)d;
        tree[rt]=(ll)(r-l+1)*d;
        lazy[rt]=1;
        return ;
    }
    pushdown(rt,l,r);
    ll mid=(l+r)>>1;
    if(L<=mid) update(l,mid,rt<<1,L,R,d);
    if(mid>1;
    ll ans=0;
    if(mid>=L) ans+=Query(l,mid,rt<<1,L,R);
    if(mid>1;
    if(maxv[rt<<1]>=v)  return Gets(l,mid,rt<<1,v);
    else return Gets(mid+1,r,rt<<1|1,v);
}

int main()
{
    while(scanf("%lld",&n)&&n)
    {
        mp.clear();
        for(ll i=1;i<=n;i++)   scanf("%lld",&seq[i]);

        ll tmp=0;
        for(ll i=1;i<=n;i++)
        {
            mp[seq[i]]++;
            while(mp.find(tmp)!=mp.end()) tmp++;
            mex[i]=tmp;
        }

        mp.clear();
        for(ll i=n;i>=1;i--)
        {
            if(mp.find(seq[i])==mp.end()) pre[i]=n+1;
            else pre[i]=mp[seq[i]];///
            mp[seq[i]]=i;
        }

        Build(1,n,1);

        ll ans=0;
        for(ll i=1;i<=n;i++)
        {
            ans += tree[1];
            if(maxv[1]>=seq[i])///细节
            {
                ll l=Gets(1,n,1,seq[i]);
                ll r=pre[i];
                if(l

 

你可能感兴趣的:(HDU习题集,线段树/zkw线段树)