题目:
Mike and !Mike are old childhood rivals, they are opposite in everything they do, except programming. Today they have a problem they cannot solve on their own, but together (with you) — who knows?
Every one of them has an integer sequences a and b of length n. Being given a query of the form of pair of integers (l, r), Mike can instantly tell the value of while !Mike can instantly tell the value of .
Now suppose a robot (you!) asks them all possible different queries of pairs of integers (l, r) (1 ≤ l ≤ r ≤ n) (so he will make exactly n(n + 1) / 2 queries) and counts how many times their answers coincide, thus for how many pairs is satisfied.
How many occasions will the robot count?
The first line contains only integer n (1 ≤ n ≤ 200 000).
The second line contains n integer numbers a1, a2, ..., an ( - 109 ≤ ai ≤ 109) — the sequence a.
The third line contains n integer numbers b1, b2, ..., bn ( - 109 ≤ bi ≤ 109) — the sequence b.
Print the only integer number — the number of occasions the robot will count, thus for how many pairs is satisfied.
6 1 2 3 2 1 4 6 7 1 2 3 2
2
3 3 3 3 1 1 1
0
The occasions in the first sample case are:
1.l = 4,r = 4 since max{2} = min{2}.
2.l = 4,r = 5 since max{2, 1} = min{2, 3}.
There are no occasions in the second sample case since Mike will answer 3 to any query pair, but !Mike will always answer 1.
给两个长度为 n (1 ≤ n ≤ 200 000)的数组a,b,求有多少个区间[l,r]满足
max(al,al+1,...ar) = min( bl,bl+1,...br )。
分析:
涉及到区间最值问题,且两数组都是静态的 优先考虑st表
问总共有多少个区间,可以从左到右另每一个下标i为左端点,找出以该下标为左端点的所有满足要求的区间
要找所有区间,由于左端点已经确定,只需要二分找到满足要求的右端点的最左下标r1和最右下标r2,则总区间数+=(r2-r1+1)
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn=201000;
int n, a[maxn], b[maxn];
int d_min[maxn][20];//第二维开到17还是小...
int d_max[maxn][20];
void RMQ_init() {
for(int i=0; i<n; i++) d_max[i][0] = a[i], d_min[i][0] = b[i];
for(int j=1; (1<<j)<=n; j++)
for(int i=0; i+(1<<j)-1<n; i++) {
d_min[i][j] = min(d_min[i][j-1], d_min[i+(1<<(j-1))][j-1]);
d_max[i][j] = max(d_max[i][j-1], d_max[i+(1<<(j-1))][j-1]);
}
}
int RMQ_min(int L, int R) {
int k = 0;
while((1<<(k+1)) <= R-L+1) k++;
return min(d_min[L][k], d_min[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(d_max[L][k], d_max[R-(1<<k)+1][k]);
}
int main(){//311 ms 35100 KB
while(scanf("%d",&n) == 1){
for(int i=0; i<n; i++) scanf("%d",&a[i]);
for(int i=0; i<n; i++) scanf("%d",&b[i]);
RMQ_init();
LL ans = 0;
for(int i=0; i<n; i++) {//枚举每一个左端点
if(a[i] > b[i]) continue;
int first_r=-1, last_r=-1;
int l=i,r=n-1,mid;
//用两次二分操作分别求出第一次和最后一次满足min==max的右端点,作差累加即可
while(l <= r) {
mid = (l+r) / 2;
if(RMQ_max(i,mid) == RMQ_min(i,mid)) first_r = mid;
if(RMQ_max(i,mid) >= RMQ_min(i,mid)) r = mid-1;
else l = mid+1;
}
if(first_r == -1) continue;
l=i; r=n-1;
while(l <= r) {
mid = (l+r) / 2;
if(RMQ_max(i,mid) > RMQ_min(i,mid)) r = mid-1;
else l = mid+1, last_r = mid;
}
ans += last_r - first_r + 1;
}
printf("%I64d\n", ans);
}
return 0;
}