和Leo一起做爱线段树的好孩子【九校2D1T3】优美序列

版权声明:LeoJAM Presents https://blog.csdn.net/fcb_x/article/details/82990259

Lxy养了N头奶牛,他把N头奶牛用1..N编号,第i头奶牛编号为i。为了让奶牛多产奶,每天早上他都会让奶牛们排成一排做早操。奶牛们是随机排列的。在奶牛排列中,如果一段区间[L,R]中的数从小到大排列后是连续的,他认为这段区间是优美的。比如奶牛排列为:(3, 1, 7, 5, 6, 4, 2),区间[3,6]是优美的,它包含4,5,6,7连续的四个数,而区间[1,3] 是不优美的。Lxy的问题是:对于给定的一个区间[L,R](1<=L<=R<=N), 他想知道,包含区间[L,R]的最短优美区间,比如区间[1,3]的最短优美区间是[1,7]。 

数据随机说明优美区间并不多

预处理出来

然后离线操作

线段树维护到当前点最短的符合条件的区间

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
inline void read(int &x){
	x=0;
	int 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();
	}
	x*=f;
}
const int N=1e5+100;
const int INF=1e9+7;
struct Segment_Tree{
	int val[N];
	struct Node{
		int lson,rson,Mx,Mn;
	}T[N<<2];
	inline void PushUp(int p){
//		T[p].Mx=max(T[lc].Mx,T[rc].Mx);
		T[p].Mn=min(T[lc].Mn,T[rc].Mn);
	}
	inline void Build(int p,int l,int r){
		T[p].lson=l;
		T[p].rson=r;
		if(l==r){
			T[p].Mn=T[p].Mx=val[l];
			return;
		}
		int mid=(l+r)>>1;
		Build(lc,l,mid);
		Build(rc,mid+1,r);
		PushUp(p);
	}
	inline void Update(int p,int pos,int val){
		if(T[p].lson==T[p].rson){
			T[p].Mn=min(T[p].Mn,val);
//			T[p].Mx=max(T[p].Mx,val);
			return;
		}
		int mid=(T[p].lson+T[p].rson)>>1;
		if(pos<=mid)Update(lc,pos,val);
		else Update(rc,pos,val);
		PushUp(p);
	}
	inline int QueryMn(int p,int l,int r){
		if(l<=T[p].lson&&T[p].rson<=r){
			return T[p].Mn;
		}
		int mid=(T[p].lson+T[p].rson)>>1;
		int ret=INF;
		if(l<=mid)ret=min(ret,QueryMn(lc,l,r));
		if(mid< r)ret=min(ret,QueryMn(rc,l,r));
		return ret;
	}
	inline int QueryMx(int p,int l,int r){
		if(l<=T[p].lson&&T[p].rson<=r){
			return T[p].Mx;
		}
		int mid=(T[p].lson+T[p].rson)>>1;
		int ret=-INF;
		if(l<=mid)ret=max(ret,QueryMx(lc,l,r));
		if(mid< r)ret=max(ret,QueryMx(rc,l,r));
		return ret;
	} 
}Tree;
int n,m;
struct ST_map{
	int val[N];
	int Mx[21][N];
	int Mn[21][N];
	void Build(){
		for(int i=1;i<=n;++i){
			Mx[0][i]=Mn[0][i]=val[i];
		}
		for(int i=1;i<=20;++i){
			for(int j=1;j<=n;++j){
				if(j+(1<<(i-1))>n)continue;
				Mx[i][j]=max(Mx[i-1][j],Mx[i-1][j+(1<<(i-1))]);
				Mn[i][j]=min(Mn[i-1][j],Mn[i-1][j+(1<<(i-1))]);
			}
		}
	}
	int QueryMx(int l,int r){
		int k=log2((double)(r-l+1));
		return max(Mx[k][l],Mx[k][r-(1<<k)+1]);
	}
	int QueryMn(int l,int r){
		int k=log2((double)(r-l+1));
		return min(Mn[k][l],Mn[k][r-(1<<k)+1]);
	}
}Sum,Loc;
struct Query{
	int l,r,Id;
}A[N];
bool cmp(Query A,Query B){
	return A.l<B.l;
}
int ans[N][2];
int F[N];
void Check(int v){
	int Mx=-INF;
	int Mn=INF;
	for(int i=v;i<=n;++i){
		Mx=max(Mx,Sum.val[i]);
		Mn=min(Mn,Sum.val[i]);
		if(Loc.QueryMn(Mn,Mx)<v)break;
		if(i-v==Mx-Mn){
			Tree.Update(1,i,i-v+1);
			F[i-v+1]=v;
		}
	}
}
int main(){
//	freopen("sequence.in","r",stdin);
//	freopen("sequence.out","w",stdout);
	read(n);
	for(int i=1;i<=n;++i){
		read(Sum.val[i]);
		Loc.val[Sum.val[i]]=i;
		Tree.val[i]=INF;
	}
	read(m);
	Sum.Build();
	Loc.Build();
	for(int i=1;i<=m;++i){
		read(A[i].l);
		read(A[i].r);
		A[i].Id=i;
	}
	sort(A+1,A+1+m,cmp);
	int now=1;
	Tree.Build(1,1,n);
	for(int i=1;i<=m;++i){
		while(now<=n&&now<=A[i].l){
			Check(now);
			++now;
		}
		int len=Tree.QueryMn(1,A[i].r,n);
		ans[A[i].Id][0]=F[len];
		ans[A[i].Id][1]=ans[A[i].Id][0]+len-1;
	}
	for(int i=1;i<=m;++i){
		cout<<ans[i][0]<<" "<<ans[i][1]<<'\n'; 
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/82990259