和Leo一起做愛線段樹的好孩子【九校2D1T3】優美序列
阿新 • • 發佈:2018-11-02
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; }