题意:首先给一个长度为n的数组,m次询问,每次询问该区间内的数是否是一个排列(从一开始)
判断一个区间内的数是否是排列 可以分成两部分考虑 首先看区间内的和是否等于前n项和,然后看区间内的数是否没有重复 两项都满足 那么就是排列
对于区间内的求和 可以通过前缀和来处理 后面区间判断是否有重复可以用线段树来判断(RMQ会超内存)线段树的每一位记录 原数组中这位上的数上一次出现的位置 每次查询区间的最大值 看是否比区间(L,R)的L大 综合起来就可以判断是否是排列了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int mod=1000000007;
const int maxn=2e6+5000;
const int inf=1e9+10000;
const int maxe=2e5+100;
int visit[maxn];
ll sum[maxn];
int a[maxn],b[maxn],pre[maxn<<2];
int qian[maxn];
void pushup(int rt){
pre[rt]=max(pre[rt<<1],pre[rt<<1|1]);
}
void update(int X,int c,int l,int r,int rt=1)
{
if(l==r)
{
pre[rt]=max(pre[rt],c);
return ;
}
int m=(l+r)>>1;
if(X<=m)update(X,c,lson);
else update(X,c,rson);
pushup(rt);
}
int query(int L,int R,int l,int r ,int rt=1)
{
if(L<=l&&r<=R)
return pre[rt];
int m=(l+r)>>1;
int ret=0;
if(L<=m)ret=max(ret,query(L,R,lson));
if(m<R)ret=max(ret,query(L,R,rson));
return ret;
}
void build(int l,int r,int rt=1)
{
if(l==r)
{
pre[rt]=b[l];
return;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
sum[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
visit[i]=0;
}
for(int i=1; i<=n; i++)
{
b[i]=visit[a[i]];
visit[a[i]]=i;
sum[i]=sum[i-1]+a[i];
}
build(1,n,1);
for(int i=0; i<m; i++)
{
int l,r;
scanf("%d%d",&l,&r);
ll len=r-l+1;
len=len*(len+1)/2;
int flag=0;
if(sum[r]-sum[l-1]==len)
{
int ans=query(l,r,1,n);
if(ans<l)
flag=1;
}
if(flag)
puts("YES");
else
puts("NO");
}
}
}