查询的是给定区间是否为全排列,那么必须满足两个条件,一个是相加之和是否为n(n+1)/2,n为区间长度,另一个就是区间内是否有重复的数,所以我们可以一个最大值,也就是记录当前值最近的位置靠前的相同值的位置,然后最大的如果在区间内,证明有重复,否则是全排列
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#define MAX 1000007
using namespace std;
typedef pair<int,int> PII;
int n,m;
int loc[MAX];
int sum[MAX];
int a;
struct Node
{
int l,r,maxn;
}tree[MAX<<2];
void push_up ( int u )
{
tree[u].maxn = max ( tree[u<<1].maxn , tree[u<<1|1].maxn );
}
void build ( int u , int left , int right )
{
tree[u].l = left , tree[u].r = right;
if ( left == right ) return;
int mid = left + right >> 1;
build ( u<<1 , left , mid );
build ( u<<1|1 , mid+1 , right );
}
void update ( int u , int x , int value )
{
int l = tree[u].l , r = tree[u].r;
if ( l == r )
{
tree[u].maxn = loc[value];
return;
}
int mid = l + r >> 1;
if ( x >= l && x <= mid ) update ( u<<1 , x , value );
if ( x > mid && x <= r ) update ( u<<1|1 , x , value );
push_up ( u );
}
int query ( int u , int left , int right )
{
int l = tree[u].l , r = tree[u].r;
if ( left <= l && r <= right )
return tree[u].maxn;
int mid = l + r >> 1;
int maxn = 0;
if ( right >= l && left <= mid )
maxn = max ( query ( u<<1 , left , right ), maxn );
if ( right > mid && left <= r )
maxn = max ( query ( u<<1|1 , left , right ) , maxn );
return maxn;
}
bool check ( int l , int r )
{
if ( (r-l+1)*(r-l+2)/2 != sum[r] - sum[l-1] ) return false;
if ( query ( 1 , l , r ) >= l ) return false;
return true;
}
void scan ( int&x )
{
char c = getchar ( );
x = 0;
while ( c < '0' || c > '9' ) c = getchar ( );
while ( c >= '0' && c <='9' )
{
x = x*10 + c - 48;
c = getchar ( );
}
}
int main ( )
{
while ( ~scanf ( "%d%d" , &n , &m ) )
{
build ( 1 , 1 , n );
memset ( loc , 0 , sizeof ( loc ) );
sum[0] = 0;
for ( int i = 1 ; i <= n ; i++ )
{
scan ( a );
update ( 1 , i , a );
loc[a] = i;
sum[i] = sum[i-1] + a;
}
int l ,r;
for ( int i = 1 ; i <= m ; i++ )
{
scan ( l );
scan ( r );
if ( check ( l , r ) ) puts ( "YES" );
else puts ( "NO" );
}
}
}