[bzoj5259][线段树]区间

版权声明:菜逼一只 https://blog.csdn.net/Rose_max/article/details/88812647

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了
我居然只想到判连续区间是用 m x m n = R L mx-mn=R-L 来判这拿头做啊…
换一个想法
如果一个区间排序后,满足 a i = a i + 1 1 a_i=a_{i+1}-1 的数对有 R L R-L 个,显然这个区间是连续区间啊.
想到这里可以有点眉目了
再证明一个小结论
我们知道覆盖一个区间的连续区间可能有很多个,那么这里仅讨论区间有交的情况。因为区间包含显然肯定有一个是不合法的。假设这两个区间为 [ L 1 , R 1 ] [L_1,R_1] [ L 2 , R 2 ] [L_2,R_2]
可以知道的是他们的交 [ L 2 , R 1 ] [L_2,R_1] 一定也是一个连续区间,不然无法和两个残余的区间均组成一个连续区间
所以某个区间的答案,一定是从他最近的R找到一个能覆盖他的L,剩余的不会有比他优秀的区间
离线询问扫右端点,把式子一拆就是 L + c a l ( l , r ) = R L+cal(l,r)=R ,其中 c a l ( l , r ) cal(l,r) 即为该区间中满足权值相邻的数对个数。把询问用一个堆存下来,每次取出 L L 最大的在线段树上找是否有合法的左端点能覆盖他
注意到我们当扫到一个 R R 时,其左边点的所有权值均不会大于 R R ,所以线段树维护一下区间最大值与最大值的位置即可
剩余是基础问题

#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;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/88812647