bzoj 3339: Rmq Problem(线段树)

3339: Rmq Problem

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 873   Solved: 428
[ Submit][ Status][ Discuss]

Description

bzoj 3339: Rmq Problem(线段树)_第1张图片

Input

bzoj 3339: Rmq Problem(线段树)_第2张图片

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

bzoj 3339: Rmq Problem(线段树)_第3张图片

Source

By Xhr

[ Submit][ Status][ Discuss]


题解:线段树

1-n 扫一遍,计算出1-i的sg值,离线所有询问,按左端点排序,预处理出每个位置的数字下一次出现的位置next。

然后左指针不断后移,从区间l-r 到区间 l+1-r ,原本sg值大于a[l]的现在都可以变成a[l],用线段树维护区间sg,每次修改l-next[a[l]]-1 的值,把a[l]的值赋给区间,然后每个区间内不断下放。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 200003
#define inf 1000000000
using namespace std;
int n,m;
int tr[N*4],b[N],mark[N],sg[N],next[N],point[N],ans[N];
int pd[N];
struct data 
{
	int l,r,num;
};data a[N];
void build(int now,int l,int r)
{
	tr[now]=inf;
	if (l==r)
	 {
	 	tr[now]=sg[l];
	 	pd[l]=now;
	 	return;
	 }
	int mid=(l+r)/2;
	build(now<<1,l,mid);
	build(now<<1|1,mid+1,r);
}
void pushdown(int x)
{
	tr[x<<1]=min(tr[x],tr[x<<1]);
	tr[x<<1|1]=min(tr[x],tr[x<<1|1]);
}
void change(int now,int l,int r,int ll,int rr,int x)
{
	if (tr[now]!=inf&&l!=r)  pushdown(now);
    if (l>=ll&&r<=rr)
     {
     	tr[now]=min(tr[now],x);
     	return;
     }
    int mid=(l+r)/2;
    if (ll<=mid)
     change(now<<1,l,mid,ll,rr,x);
    if (rr>mid)
     change(now<<1|1,mid+1,r,ll,rr,x);
}
int cmp(data a,data b)
{
	return a.l<b.l;
}
int ask(int now,int l,int r,int x)
{
	if (tr[now]!=inf&&l!=r) pushdown(now);
	if (l==r) return tr[now];
	int mid=(l+r)/2;
	if (x<=mid)
	 return ask(now<<1,l,mid,x);
	else
	 return ask(now<<1|1,mid+1,r,x);
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) 
	  scanf("%d",&b[i]);
	int k=0;
	for (int i=1;i<=n;i++)
	 {
	 	mark[b[i]]=1;
	 	if (b[i]==k)
	 	 while (mark[k]) k++;
	 	sg[i]=k;
	 }
    for (int i=1;i<=n;i++)
     point[b[i]]=n+1;
	for (int i=n;i>=1;i--)
	 {
	 	next[i]=point[b[i]]; point[b[i]]=i;
	 }
	for (int i=1;i<=m;i++)
	 scanf("%d%d",&a[i].l,&a[i].r),a[i].num=i;
	sort(a+1,a+m+1,cmp);
	build(1,1,n);
	int l=1;
	for (int i=1;i<=m;i++)
	 {
	 	while (l<a[i].l)
	 	{
	 		int r;
	 		r=next[l]-1; 
	 	    change(1,1,n,l,r,b[l]);
	 	    l++;
	 	}
	 	ans[a[i].num]=ask(1,1,n,a[i].r);
	 }
	for (int i=1;i<=m;i++)
	 printf("%d\n",ans[i]);
}



你可能感兴趣的:(bzoj 3339: Rmq Problem(线段树))