3339: Rmq Problem
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 873 Solved: 428
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7
Sample Output
3
0
3
2
4
0
3
2
4
HINT
Source
题解:线段树
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]);
}