1. 程式人生 > >和Leo一起做愛線段樹的好孩子【九校2D1T3】優美序列

和Leo一起做愛線段樹的好孩子【九校2D1T3】優美序列

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