题目大意:
给出
n
个数,定义一种好点对
1.
i=j−1
2.对于
∨k∈(i,j)
,均有
a[k]<min(a[i],a[j])
询问若干个区间中的好点对个数。
题解:
我们首先可以发现,这样的好点对是不相交的(但会出现包含情况),既不可能出现两个好点对
(i1,j1),(i2,j2)
,使得
j1>i2
且
j1<j2
,因为那样的话这两个好点对就会变成
(i1,i2),(j1,j2)
。
那这样的话我们可以预处理出来以每个点作为
i
和
然后我们需要知道一个区间中的最大值,这个用
ST
表
O(nlog(n))
的预处理一下就可以
O(1)
的查询。
对于每个询问区间
[l,r]
,我们先查出区间的最大值,有两种情况:
1.如果这个最大值是
l
或
2.如果是在区间中间,那就以这个最大值为界,将原区间分成
[l,maxx],[maxx,r]
,那这两个区间就都变成了情况1。
Ps.
答案不会超过
2n
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 300010
#define LL long long
int n,m,a[N],q[N<<1],l[N],r[N],st[N][20],w[N],ans,sl[N],sr[N];
inline int in(){
int x=0; char ch=getchar(); bool f=1;
while (ch<'0'||ch>'9'){
if (ch=='-') f=0;
ch=getchar();
}while (ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
if (!f) x=-x; return x;
}
inline void Init(){
int i,j,top=1,x,y; q[top]=1;
for (i=2; i<=n; i++){
while (top&&a[i]>a[q[top]]) r[i]++,top--;
if (top) r[i]++;
while (top&&a[i]>=a[q[top]]) top--;
q[++top]=i;
}for (i=1; i<=n; i++) sr[i]=sr[i-1]+r[i];
top=1,q[top]=n;
for (i=n-1; i>=1; i--){
while (top&&a[i]>a[q[top]]) l[i]++,top--;
if (top) l[i]++;
while (top&&a[i]>=a[q[top]]) top--;
q[++top]=i;
}for (i=1; i<=n; i++) sl[i]=sl[i-1]+l[i];
for (i=1; i<=n; i++) st[i][0]=i;
for (j=1; (1<<j)<=n; j++)
for (i=1; i+(1<<(j-1))<=n; i++){
x=st[i][j-1],y=st[i+(1<<(j-1))][j-1];
if (a[x]>a[y]) st[i][j]=x;
else st[i][j]=y;
}
for (i=1,j=0; i<=n; i++){
if ((1<<(j+1))<=i) j++;
w[i]=j;
}
}
inline int query(int l,int r){
int k=w[r-l],x,y;
x=st[l][k],y=st[r-(1<<k)+1][k];
if (a[x]>a[y]) return x;
else return y;
}
inline void work(int l,int r){
int x=query(l,r);
if (a[x]>=min(a[l],a[r]))
ans=sl[x-1]-sl[l-1]+sr[r]-sr[x];
else ans=sl[r]-sl[l-1];
printf("%d\n",ans);
}
int main(){
int i,l,r,opt;
n=in(),m=in(),opt=in();
for (i=1; i<=n; i++) a[i]=in();
Init(),ans=0;
for (i=1; i<=m; i++){
l=in(),r=in();
if (opt) l=(l+ans-1)%n+1,r=(r+ans-1)%n+1;
if (l>r) swap(l,r); work(l,r);
}return 0;
}