Description
给定一个1到n的排列a1, . . . , an。
对于一个区间[l, r],我们称该区间是连续的,如果将al, . . . , ar排列之后得到的是一列连续的数。
(换句话说,如果x,y都在该区间中,那么所有介于x,y之间的数也在该区间中)
现在有m(1 ≤ n, m ≤ 100000)个询问,每个询问给出一个区间[xi, yi],
你需要找到一个长度最短的连续区间[li,ri],使得[xi,yi]属于 [li, ri]。
Solution
考虑如何判断一个区间是连续段,当且仅当区间内
(
x
,
x
+
1
)
(x,x+1)
(x,x+1)的对数为
r
−
l
r-l
r−l。
设区间
[
l
,
r
]
[l,r]
[l,r]内
(
x
,
x
+
1
)
(x,x+1)
(x,x+1)的对数为
c
(
l
,
r
)
c(l,r)
c(l,r)。
我们可以枚举右端点
r
r
r,用线段树维护
l
+
c
(
l
,
r
)
l+c(l,r)
l+c(l,r)。可以发现合法仅当
l
+
c
(
l
,
r
)
=
r
l+c(l,r)=r
l+c(l,r)=r,并且
l
+
c
(
l
,
r
)
l+c(l,r)
l+c(l,r)最大值为
r
r
r,所以只需要维护最大值以及最大值的位置就可以了。
实现的时候把所有询问离线,枚举到了询问的
r
r
r端点就把询问丢进一个优先队列里面,以询问的
l
l
l端点为关键字,堆顶是
l
l
l最大的。每次如果能找到答案就pop,否则就break,因为查询的是
[
1
,
l
]
[1,l]
[1,l]的最大值,
l
l
l越大一定越容易找到答案。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
#define pa pair<int,int>
#define LL long long
const int Maxn=100010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,a[Maxn],pos[Maxn],m;
struct Seg{int lc,rc,l,r,mx,tag,pos;}tr[Maxn<<1];
int tot=0;
void Add(int x,int v){tr[x].mx+=v,tr[x].tag+=v;}
void up(int x)
{
int lc=tr[x].lc,rc=tr[x].rc;
if(tr[rc].mx>=tr[lc].mx)tr[x].pos=tr[rc].pos;
else tr[x].pos=tr[lc].pos;
tr[x].mx=max(tr[lc].mx,tr[rc].mx);
}
void down(int x)
{
int lc=tr[x].lc,rc=tr[x].rc,t=tr[x].tag;
if(t)tr[x].tag=0,Add(lc,t),Add(rc,t);
}
void build(int l,int r)
{
int x=++tot;
tr[x].l=l;tr[x].r=r;tr[x].tag=0;
if(l==r){tr[x].pos=tr[x].mx=l;return;}
int mid=l+r>>1;
tr[x].lc=tot+1,build(l,mid);
tr[x].rc=tot+1,build(mid+1,r);
up(x);
}
void add(int x,int l,int r,int v)
{
if(tr[x].l==l&&tr[x].r==r){Add(x,v);return;}
int lc=tr[x].lc,rc=tr[x].rc,mid=tr[x].l+tr[x].r>>1;
down(x);
if(r<=mid)add(lc,l,r,v);
else if(l>mid)add(rc,l,r,v);
else add(lc,l,mid,v),add(rc,mid+1,r,v);
up(x);
}
int Mx,Pos;
void query(int x,int l,int r)
{
if(tr[x].l==l&&tr[x].r==r)
{
if(tr[x].mx>=Mx)Mx=tr[x].mx,Pos=tr[x].pos;
return;
}
int lc=tr[x].lc,rc=tr[x].rc,mid=tr[x].l+tr[x].r>>1;
down(x);
if(r<=mid)query(lc,l,r);
else if(l>mid)query(rc,l,r);
else query(lc,l,mid),query(rc,mid+1,r);
}
struct P{int l,id;P(int _l,int _id){l=_l,id=_id;}};
bool operator<(P a,P b){return a.l<b.l;}
vector<P>h[Maxn];
priority_queue<P>q;
int ans[Maxn][2];
int main()
{
n=read();
for(int i=1;i<=n;i++)a[i]=read();
build(1,n);
m=read();
for(int i=1;i<=m;i++)
{
int l=read(),r=read();
h[r].push_back(P(l,i));
}
for(int i=1;i<=n;i++)
{
int x=a[i];
if(x!=1&&pos[x-1])add(1,1,pos[x-1],1);
if(x!=n&&pos[x+1])add(1,1,pos[x+1],1);
pos[x]=i;
for(int j=0;j<h[i].size();j++)q.push(h[i][j]);
while(!q.empty())
{
P t=q.top();
Mx=-inf;
query(1,1,t.l);
if(Mx!=i)break;
q.pop();
ans[t.id][0]=Pos,ans[t.id][1]=i;
}
}
for(int i=1;i<=m;i++)printf("%d %d\n",ans[i][0],ans[i][1]);
}