码迷,mamicode.com
首页 > 其他好文 > 详细

HDU-4747 Mex(线段树区间更新)

时间:2016-07-31 17:20:40      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:给一个长度为n的整数序列,定义mex(i,j)表示区间[i,j]中没有出现过的最小非负整数,求sigma(mex(i,j)),即序列中所有连续非空子区间的mex之和。

题目分析:

answer=mex(1,1)+mex(1,2)...mex(1,n)
+ mex(2,2)...mex(2,n)
.
.
.
+ mex(n,n)。

  初始时,用线段树的叶子节点维护mex(1,i),将a(1)从序列中拿去后,将叶子节点的维护信息更新为mex(2,i),以此类推...没更新一次,便求一次区间和,总和即为答案。

  当拿掉a(i)后,只有a(k)以前的mex(i+1,j)将会受到影响,其中k>i并且a(i)=a(k)。

  当i+1<=j<k时,如果mex(i,j)>a(i),那么mex(i+1,j)=a(i),否则mex(i+1,j)=mex(i,j)。显然,当 i 固定时,mex(i,j)关于 j 单调不减。所以,mex(i,j)>a(i)的将会是一段区间。

 

代码如下:

# include<bits/stdc++.h>
using namespace std;
# define LL long long
# define mid (l+(r-l)/2)

const int N=200000;

int a[N+5];
int mex[N+5];
int nxt[N+5];
LL tr[N*4+5];
LL lazy[N*4+5];
int maxn[N*4+5];

inline void getMex(int n)
{
	map<int,int>mp;
	map<int,int>f;
	fill(nxt,nxt+1+n,n+1);
	int m=0;
	for(int i=1;i<=n;++i){
		mp[a[i]]=1;
		while(mp[m]) ++m;
		mex[i]=m;
		if(f[a[i]])
			nxt[f[a[i]]]=i;
		f[a[i]]=i;
	}
}

inline void pushUp(int rt)
{
	tr[rt]=tr[rt<<1]+tr[rt<<1|1];
	maxn[rt]=max(maxn[rt<<1],maxn[rt<<1|1]);
}

inline void pushDown(int rt,int l,int r)
{
	if(lazy[rt]!=-1){
		lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
		maxn[rt<<1]=maxn[rt<<1|1]=lazy[rt];
		tr[rt<<1]=lazy[rt]*(LL)(mid-l+1);
		tr[rt<<1|1]=lazy[rt]*(LL)(r-mid);
		lazy[rt]=-1;
	}
}

inline void build(int rt,int l,int r)
{
	lazy[rt]=-1;
	if(l==r){
		tr[rt]=mex[l];
		maxn[rt]=mex[l];
	}else{
		build(rt<<1,l,mid);
		build(rt<<1|1,mid+1,r);
		pushUp(rt);
	}
}

inline int query_up(int rt,int l,int r,int L,int R,int x)
{
	if(l==r){
		if(tr[rt]<x) return 0;
		return l;
	}
	pushDown(rt,l,r);
	if(L<=mid&&x<maxn[rt<<1]){
		int k=query_up(rt<<1,l,mid,L,R,x);
		if(k>0) return k;
	}
	if(R>mid&&x<maxn[rt<<1|1]){
		int k=query_up(rt<<1|1,mid+1,r,L,R,x);
		if(k>0) return k;
	}
	return 0;
}

inline void update(int rt,int l,int r,int L,int R,int x)
{
	if(L<=l&&r<=R){
		lazy[rt]=x;
		tr[rt]=(LL)x*(LL)(r-l+1);
		maxn[rt]=x;
	}else{
		pushDown(rt,l,r);
		if(L<=mid) update(rt<<1,l,mid,L,R,x);
		if(R>mid) update(rt<<1|1,mid+1,r,L,R,x);
		pushUp(rt);
	}
}

inline LL query(int rt,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return tr[rt];
	pushDown(rt,l,r);
	LL res=0;
	if(L<=mid) res+=query(rt<<1,l,mid,L,R);
	if(R>mid) res+=query(rt<<1|1,mid+1,r,L,R);
	return res;
}

int main()
{
	int n;
	while(scanf("%d",&n)&&n)
	{
		for(int i=1;i<=n;++i) scanf("%d",a+i);
		getMex(n);
		build(1,1,n);
		LL ans=query(1,1,n,1,n);
		for(int i=1;i<n;++i){
			int p=query_up(1,1,n,i+1,nxt[i]-1,a[i]);
			if(p>0) update(1,1,n,p,nxt[i]-1,a[i]);
			ans+=query(1,1,n,i+1,n);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

  

HDU-4747 Mex(线段树区间更新)

标签:

原文地址:http://www.cnblogs.com/20143605--pcx/p/5723148.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!