您的位置:首页 > 其它

hdu 4747 Mex(线段树)

2014-04-30 13:36 477 查看


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

2013 ACM/ICPC Asia Regional Hangzhou Online

题意:记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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: