bzoj3339 Rmq Problem

3339: Rmq Problem

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 742   Solved: 360
[ Submit][ Status][ Discuss]

Description

Input

bzoj3339 Rmq Problem_第1张图片

Output

Sample Input

7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7

Sample Output

3
0
3
2
4

HINT

bzoj3339 Rmq Problem_第2张图片

Source

By Xhr




一道思路很不错的题!

首先这道题是支持离线的,所以我们可以先将所有询问按左端点从小到大排序。

然后这样考虑:

我们可以通过O(n)的方法求出区间[1,i]的mex值。(1≤i≤n)

接着考虑区间[l,r]和[l+1,r]mex值的区别。可以发现如果r≥next[i],两个区间的mex值是相同的。如果是r<next[i]的情况呢?显然只需要将区间内大于a[l]的mex值修改为a[l],即区间取min操作。(其中next[i]表示在点i之后第一个与a[i]相同的点的位置,这个也是可以预处理出的)

于是这道题就转化为在区间内取min操作和单点查询,显然用线段树实现。

Tips:

① 这道题将所有询问排序(离线)和转化为区间修改的方法很巧妙。

② 线段树中的叶子节点表示区间[now,i]的mex值(其中now为当前左端点,i为叶节点对应的位置);线段树中的非叶子节点并没有实际含义,只是为了修改操作的方便。




#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
#define pa pair<int,int>
#define MAXN 200005
#define INF 1000000000
using namespace std;
struct tree_type
{
	int l,r,mn;
}t[MAXN*4];
struct data
{
	int l,r,num;
}b[MAXN];
int n,m,tmp=0,now=1,a[MAXN],f[MAXN],next[MAXN],last[MAXN],ans[MAXN];
bool mark[MAXN];
int read()
{
	int ret=0,flag=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') flag=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
	return ret*flag;
}
void build(int k,int l,int r)
{
	t[k].l=l;
	t[k].r=r;
	if (l==r)
	{
		t[k].mn=f[l];
		return;
	}
	t[k].mn=INF;
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}
void pushdown(int k)
{
	if (t[k].mn==INF) return;
	t[k<<1].mn=min(t[k<<1].mn,t[k].mn);
	t[k<<1|1].mn=min(t[k<<1|1].mn,t[k].mn);
	t[k].mn=INF;
}
void change(int k,int x,int y,int z)
{
	if (t[k].l==x&&t[k].r==y)
	{
		t[k].mn=min(t[k].mn,z);
		return;
	}
	pushdown(k);
	int mid=(t[k].l+t[k].r)>>1;
	if (mid>=y) change(k<<1,x,y,z);
	else if (mid+1<=x) change(k<<1|1,x,y,z);
	else change(k<<1,x,mid,z),change(k<<1|1,mid+1,y,z);
}
int query(int k,int x)
{
	if (t[k].l==t[k].r) return t[k].mn;
	pushdown(k);
	int mid=(t[k].l+t[k].r)>>1;
	if (x<=mid) return query(k<<1,x);
	else return query(k<<1|1,x);
}
bool cmp(data x,data y)
{
	return x.l<y.l;
}
int main()
{
	memset(mark,false,sizeof(mark));
	memset(next,0,sizeof(next));
	memset(last,0,sizeof(last));
	n=read();m=read();
	F(i,1,n) a[i]=read();
	F(i,1,n)
	{
		mark[a[i]]=true;
		while (mark[tmp]) tmp++;
		f[i]=tmp;
	}
	build(1,1,n);
	D(i,n,1)
	{
		next[i]=last[a[i]];
		last[a[i]]=i;
	}
	F(i,1,m)
	{
		b[i].l=read();
		b[i].r=read();
		b[i].num=i;
	}
	sort(b+1,b+m+1,cmp);
	F(i,1,m)
	{
		while (now<b[i].l)
		{
			if (!next[now]) next[now]=n+1;
			change(1,now,next[now]-1,a[now]);
			now++;
		}
		ans[b[i].num]=query(1,b[i].r);
	}
	F(i,1,m) printf("%d\n",ans[i]);
	return 0;
}


你可能感兴趣的:(bzoj)