Description
Input
Output
Sample Input
3 2 0
2 1 2
1 1
1 3
2 1 2
1 1
1 3
Sample Output
0
3
3
HINT
M,N<=3*10^5,Ai<=10^9
题解:可以发现点对数不会大于2*n,且点对之间不跨立.
所以我们可以先用单调栈求出所有的点对,主席树维护一下即可.
注意处理数值相等的情况.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300010
using namespace std;
int a[N],ls[N*42],rs[N*42],sum[N*42],n,m,tp,cnt,num,top,l,r,ans,root[N];
struct use{int val,id;}q[N];
struct point{int l,r;}p[N*2];
bool cmp(point a,point b){return a.l==b.l?a.r<b.r:a.l<b.l;}
int read(){
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
void insert(int x,int &y,int l,int r,int p){
y=++cnt;
ls[y]=ls[x];rs[y]=rs[x];
if (l==r) {sum[y]=sum[x]+1;return;}
int mid=(l+r)>>1;
if (p<=mid) insert(ls[x],ls[y],l,mid,p);
else insert(rs[x],rs[y],mid+1,r,p);
sum[y]=sum[ls[y]]+sum[rs[y]];
}
int query(int x,int y,int l,int r,int ll,int rr){
int mid=(l+r)>>1;
if (ll==l&&r==rr) return sum[y]-sum[x];
if (rr<=mid) return query(ls[x],ls[y],l,mid,ll,rr);
else if (mid<ll) return query(rs[x],rs[y],mid+1,r,ll,rr);
else return query(ls[x],ls[y],l,mid,ll,mid)+query(rs[x],rs[y],mid+1,r,mid+1,rr);
}
int main(){
n=read();m=read();tp=read();
for (int i=1;i<=n;i++) a[i]=read();
top=0;num=0;
for (int i=1;i<=n;i++){
int flag(0);
while (top&&a[i]>=q[top].val){p[++num]=point{q[top].id,i};if (a[i]==q[top].val) flag=1;top--;}
if (top&&!flag) p[++num]=point{q[top].id,i};
q[++top]=use{a[i],i};
}
sort(p+1,p+num+1,cmp);top=1;
for (int i=1;i<=n;i++){
root[i]=root[i-1];
while (top<=num&&p[top].l==i){insert(root[i],root[i],1,n,p[top].r);top++;}
}
for (int i=1;i<=m;i++){
l=read();r=read();
if(tp){l=(l+ans-1)%n+1;r=(r+ans-1)%n+1;if (l>r)swap(l,r);}
ans=query(root[l-1],root[r],1,n,l,r);
printf("%d\n",ans);
}
}