BZOJ3339: Rmq Problem 线段树

BZOJ 3339: Rmq Problem

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 1004   Solved: 507

题解:
可以将询问离线处理。按照左端点从小到大排序,若左端点相同则按右端点排序
首先,我们可以直接求出来mex(1,1~n)
预处理出来nxt,nxt[i]表示和i位置数值相同的下一个数字的下标,当左端点进行转移时,从j到nxt[j]-1的答案就要和a[j]取一下min,既然是对区间取min,我们可以用线段树来解决,线段树上的点权表示询问的右端点为该点时答案是多少
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=200005;
const int inf=1e9;
struct segmenttree{int l,r,mn,lazy;}T[N*4];
struct qur{int l,r,num;} Q[N];
int n,m,a[N],nxt[N],lj[N],SG[N],ans[N];
bool b[N];
bool cmp(qur u,qur v)
{
	if(u.l==v.l) return u.r<v.r;
	return u.l<v.l;
}
void Pushdown(int x)
{
	int lc=x<<1,rc=x<<1|1;
	T[lc].mn=min(T[x].lazy,T[lc].mn);
	T[rc].mn=min(T[x].lazy,T[rc].mn);
	T[lc].lazy=min(T[lc].lazy,T[x].lazy);
	T[rc].lazy=min(T[rc].lazy,T[x].lazy);
	T[x].lazy=inf;
}
void Pushup(int x)
{
	T[x].mn=min(T[x<<1].mn,T[x<<1|1].mn);
} 
void Build(int x,int l,int r)
{
	T[x].l=l,T[x].r=r,T[x].lazy=inf;
	if(l==r)
	{
		T[x].mn=SG[l];
		return;
	}
	int mid=(l+r)>>1;
	Build(x<<1,l,mid);
	Build(x<<1|1,mid+1,r);
	Pushup(x);
}
void Modify(int x,int l,int r,int v)
{
	if(T[x].l==l&&T[x].r==r)
	{
		T[x].mn=min(v,T[x].mn);
		T[x].lazy=min(v,T[x].lazy);
		return;
	}
	if(T[x].lazy!=inf) Pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) Modify(x<<1,l,r,v);
	else if(l>mid) Modify(x<<1|1,mid+1,r,v);
	else Modify(x<<1,l,mid,v),Modify(x<<1|1,mid+1,r,v);
	Pushup(x);
}
int Query(int x,int k)
{
	if(T[x].l==T[x].r) return T[x].mn;
	if(T[x].lazy!=inf) Pushdown(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(k<=mid) return Query(x<<1,k);
	else return Query(x<<1|1,k);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=n;i>=1;i--) nxt[i]=lj[a[i]],lj[a[i]]=i;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&Q[i].l,&Q[i].r);
		Q[i].num=i;
	}
	int now=0;
	for(int i=1;i<=n;i++)
	{
		b[a[i]]=true;
		while(b[now]==true) now++;
		SG[i]=now;
	}
	Build(1,1,n);
	sort(Q+1,Q+m+1,cmp);
	Q[0].l=1;
	for(int i=1;i<=m;i++)
	{
		for(int j=Q[i-1].l;j<Q[i].l;j++)
		{
			if(nxt[j]==0) nxt[j]=n+1;
		 	Modify(1,j,nxt[j]-1,a[j]);
		}
		ans[Q[i].num]=Query(1,Q[i].r);
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}

Description

Input

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

Source

[Submit][Status][Discuss]

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值