题目:
题意:
给A,B两个序列,求 maxri=l(Ai)=minri=l(Bi) 的区间数量
思路:
在所有的区间中求极大/小值,第一反应就应该是二分。
当l为定值,随着x的增大,
maxxl=iArri
是一个单调不减函数,同理,
minxl=iArri
是一个单调不增函数,这里不给出证明,有兴趣自己想一下为什么。
有了上面的规律,很容易想到算法:用RMQ做预处理,然后枚举区间左值,二分区间右值,找到两个函数的相交部分即可,因为不是严格递增递减函数,所以相交部分有可能是一段而不仅仅是一个点,所以做两次二分,一次找到相交部分的左端点,一次找到右端点
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
int dmin[maxn][32], dmax[maxn][32];
void RMQ_init(int A[], int B[], int len){
for (int i = 0; i<len; ++i){
dmin[i][0] = A[i];
dmax[i][0] = B[i];
}
for (int j = 1; (1 << j) <= len; ++j)
for (int i = 0; i + (1 << j) - 1<len; ++i){
dmin[i][j] = min(dmin[i][j - 1], dmin[i + (1 << (j - 1))][j - 1]);
dmax[i][j] = max(dmax[i][j - 1], dmax[i + (1 << (j - 1))][j - 1]);
}
return;
}
int RMQ_min(int L, int R){
int k = 0;
while (1 << (k + 1) <= R - L + 1) k++;
return min(dmin[L][k], dmin[R - (1 << k) + 1][k]);
}
int RMQ_max(int L, int R){
int k = 0;
while (1 << (k + 1) <= R - L + 1) k++;
return max(dmax[L][k], dmax[R - (1 << k) + 1][k]);
}
int arr1[maxn], arr2[maxn];
int main(){
int n;
scanf("%d",&n);
for (int i=0;i<n;++i)
scanf("%d",arr1+i);
for (int i=0;i<n;++i)
scanf("%d",arr2+i);
RMQ_init(arr2, arr1, n);
long long sum = 0;
for (int i=0;i<n;++i){
int l = i, r = n-1, res1 = -1, res2 = -1;
if (RMQ_min(l,r)>RMQ_max(l,r)) continue;
while (l<=r){
int mid = (l+r) >> 1;
int minimum = RMQ_min(i,mid), maximum = RMQ_max(i,mid);
if (minimum == maximum)
res1 = res1 == -1 ? mid : max(res1, mid);
if (minimum < maximum)
r = mid - 1;
else
l = mid + 1;
}
if (res1 == -1) continue;
l = i, r = res1, res2 = -1;
while (l<=r){
int mid = (l+r) >> 1;
int minimum = RMQ_min(i,mid), maximum = RMQ_max(i,mid);
if (minimum == maximum)
res2 = res2 == -1 ? mid : min(res2, mid);
if (minimum <= maximum)
r = mid - 1;
else
l = mid + 1;
}
sum += res1 - res2 + 1;
}
cout<<sum<<endl;
return 0;
}