题意:
GTY有n个朋友,站成一排,每个人有一个特征值ai。
有m个询问。每次询问给两个数L,R。问你[L,R](即aL...aR)是否是1..(R-L+1)的一个全排列。
是输出YES,否则输出NO
思路:
先判断是否segma(a[L,R])是否等于(R-L)*(R-L+1)/2。
记录每一个ai上一次的位置pre[i]。
这样只要判断a[L]...a[R]中的每一个pre[i]是否都小于L即可。(这个方法太妙)
线段树区间求最大值。
*用map效率明显下降。
代码:
int const N = 1000005; int n,m; int a[N]; ll sum[N]; int pre[N]; int F[N<<4]; int lastPos[N]; void PushUp(int rt){ F[rt]=max( F[rt<<1],F[rt<<1|1] ); } void build(int l,int r,int rt){ if(l==r){ F[rt]=pre[l]; return; } int m=(l+r)>>1; build(lson); build(rson); PushUp(rt); } int query(int L,int R,int l,int r,int rt){ if(L<=l && r<=R){ return F[rt]; } int m=(l+r)>>1; int ret=0; if(L<=m) ret=max( ret,query(L,R,lson) ); if(R>m) ret=max( ret,query(L,R,rson) ); return ret; } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ sum[0]=0; rep(i,1,n){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } mem(lastPos,0); rep(i,1,n){ pre[i]=lastPos[a[i]]; lastPos[a[i]]=i; } build(1,n,1); while(m--){ int L,R; scanf("%d%d",&L,&R); ll temp=(ll)1*(R-L+2)*(R-L+1)/2; if( ((sum[R]-sum[L-1])==temp)&&query(L,R,1,n,1)<L ){ puts("YES"); } else{ puts("NO"); } } } return 0; }