题目大意:
给出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;
}
本文介绍了一种求解特定区间内好点对数量的问题,通过预处理和使用单调栈来快速查找,结合前缀和与ST表实现高效查询。
1270

被折叠的 条评论
为什么被折叠?



