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]。
Input
第1行1个数n。 第2行n个数a1,…an(a1, . . . , an为1到n的排列)。 第3行1个数m。
第4行到第m+3行,每行2个数xi,yi(1 ≤ xi ≤ yi ≤ n)。
Output
输出共m行,每行两个数li,ri,含义如题目所述。
Sample Input
7
3 1 7 5 6 4 2
3
3 6
7 7
1 3
Sample Output
3 6
7 7
1 7
题解
换句话来说 还是naive了
我居然只想到判连续区间是用 来判这拿头做啊…
换一个想法
如果一个区间排序后,满足 的数对有 个,显然这个区间是连续区间啊.
想到这里可以有点眉目了
再证明一个小结论
我们知道覆盖一个区间的连续区间可能有很多个,那么这里仅讨论区间有交的情况。因为区间包含显然肯定有一个是不合法的。假设这两个区间为 与
可以知道的是他们的交 一定也是一个连续区间,不然无法和两个残余的区间均组成一个连续区间
所以某个区间的答案,一定是从他最近的R找到一个能覆盖他的L,剩余的不会有比他优秀的区间
离线询问扫右端点,把式子一拆就是 ,其中 即为该区间中满足权值相邻的数对个数。把询问用一个堆存下来,每次取出 最大的在线段树上找是否有合法的左端点能覆盖他
注意到我们当扫到一个 时,其左边点的所有权值均不会大于 ,所以线段树维护一下区间最大值与最大值的位置即可
剩余是基础问题
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline int read()
{
int f=1,x=0;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 stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=100005;
vector<pii> vec[MAXN];
priority_queue<pii> hp;
struct segtree
{
int mx[MAXN*4],pos[MAXN*4],lazy[MAXN*4];
void up(int now)
{
mx[now]=max(mx[lc],mx[rc]);
if(mx[lc]>mx[rc])pos[now]=pos[lc];
else pos[now]=pos[rc];
}
void buildtree(int now,int l,int r)
{
if(l==r){mx[now]=pos[now]=l;return ;}
int mid=(l+r)/2;
buildtree(lc,l,mid);buildtree(rc,mid+1,r);
up(now);
}
void down(int now)
{
if(!lazy[now])return ;
mx[lc]+=lazy[now];mx[rc]+=lazy[now];
lazy[lc]+=lazy[now];lazy[rc]+=lazy[now];
lazy[now]=0;
}
void modify(int now,int l,int r,int ql,int qr,int c)
{
if(l==ql&&r==qr){mx[now]+=c;lazy[now]+=c;return ;}
int mid=(l+r)/2;down(now);
if(qr<=mid)modify(lc,l,mid,ql,qr,c);
else if(mid+1<=ql)modify(rc,mid+1,r,ql,qr,c);
else modify(lc,l,mid,ql,mid,c),modify(rc,mid+1,r,mid+1,qr,c);
up(now);
}
pii getpos(int now,int l,int r,int ql,int qr)
{
if(l==ql&&r==qr)return mp(mx[now],pos[now]);
int mid=(l+r)/2;down(now);
if(qr<=mid)return getpos(lc,l,mid,ql,qr);
else if(mid+1<=ql)return getpos(rc,mid+1,r,ql,qr);
else
{
pii u=getpos(lc,l,mid,ql,mid),v=getpos(rc,mid+1,r,mid+1,qr);
if(u.first>v.first)return u;
return v;
}
}
}seg;
int n,a[MAXN],lst[MAXN],nxt[MAXN],m,asl[MAXN],asr[MAXN];
int id[MAXN];
int main()
{
n=read();
memset(id,63,sizeof(id));
for(int i=1;i<=n;i++)a[i]=read(),id[a[i]]=i;
for(int i=1;i<=n;i++)lst[i]=id[a[i]-1],nxt[i]=id[a[i]+1];
m=read();
for(int i=1;i<=m;i++)
{
int l=read(),r=read();
vec[r].push_back(mp(l,i));
}
seg.buildtree(1,1,n);
for(int i=1;i<=n;i++)
{
if(lst[i]<=i)seg.modify(1,1,n,1,lst[i],1);
if(nxt[i]<=i)seg.modify(1,1,n,1,nxt[i],1);
for(int j=0;j<vec[i].size();j++)hp.push(vec[i][j]);
bool flag=1;
while(flag)
{
flag=false;
if(hp.empty())continue;
pii temp=hp.top();
pii now=seg.getpos(1,1,n,1,temp.first);
if(now.first==i)
{
hp.pop();
asl[temp.second]=now.second;
asr[temp.second]=i;
flag=true;
}
}
}
for(int i=1;i<=m;i++)pr1(asl[i]),pr2(asr[i]);
return 0;
}