codeforces 361 D - Friends and Subsequences
原题:
Description
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?
Input
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.
Output
Print the only integer number — the number of occasions the robot will count, thus for how many pairs is satisfied.
Sample Input
6
1 2 3 2 1 4
6 7 1 2 3 2
2
3
3 3 3
1 1 1
0
Hint
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^2)无法通过。
观察发现,如果固定区间左边界L,右边界R一次递增,a_max【L,R】是不减的,即有序。 同样b_min【L,R】是不增的,有序。
所以就可以先枚举左端点,再用二分法去寻找右端点的合法(符合题意的)区间,这个区间会是一个连续的范围。
二分的时候注意 RMQ_a(L,mid) = RMQ_b(L,mid) 的时候如何处理决定了最终结果是右端点的左边界还是右边界。
求区间最值是使用了RMQ算法。(一个很精妙的算法,我之前的博客里有写。)
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define MAX(x,y) (((x)>(y)) ? (x) : (y))
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define ABS(x) ((x)>0?(x):-(x))
#define ll long long
const int inf = 0x7fffffff;
const int maxn=2e5+10;
int a[maxn],b[maxn];
int d_a[maxn][23];
int d_b[maxn][23];
void RMQ_init_a(int *A,int n)
{
for(int i=0; i<n; i++) d_a[i][0]=A[i];
for(int j=1; (1<<j)-1 < n; j++)
for(int i=0; i+(1<<j)-1 < n; i++)
d_a[i][j]=MAX( d_a[i][j-1], d_a[i + (1<<(j-1))][j-1] );
}
int RMQ_a(int L, int R)
{
int k=0;
while( 1<<(k+1) <= R-L+1 ) k++;
return MAX( d_a[L][k], d_a[R-(1<<k) + 1][k] );
}
void RMQ_init_b(int *A,int n)
{
for(int i=0; i<n; i++) d_b[i][0]=A[i];
for(int j=1; (1<<j)-1 < n; j++)
for(int i=0; i+(1<<j)-1 < n; i++)
d_b[i][j]=MIN( d_b[i][j-1], d_b[i + (1<<(j-1))][j-1] );
}
int RMQ_b(int L, int R)
{
int k=0;
while( 1<<(k+1) <= R-L+1 ) k++;
return MIN( d_b[L][k], d_b[R-(1<<k) + 1][k] );
}
int main()
{
int n;
cin>>n;
for(int i=0; i<n; i++) scanf("%d",a+i);
for(int i=0; i<n; i++) scanf("%d",b+i);
RMQ_init_a(a,n);
RMQ_init_b(b,n);
int left, right;
ll ans = 0;
for(int L=0; L<n; L++)
{
int left = inf, right = -inf;
//求左边界
int l = L;
int r = n-1;
while(l <= r)
{
int mid=(l + r)/2;
if(RMQ_a(L,mid) > RMQ_b(L,mid)) //左半部分
r=mid-1;
else if(RMQ_a(L,mid) < RMQ_b(L,mid)) //右半部分
l=mid+1;
else
{
left = min(left, mid);
r=mid-1;
}
}
// printf("left = %d\n",left);
//求右边界
l = L;
r = n-1;
while(l <= r)
{
int mid=(l + r)/2;
if(RMQ_a(L,mid) > RMQ_b(L,mid)) //左半部分
{
r=mid-1;
}
else if(RMQ_a(L,mid) < RMQ_b(L,mid)) //右半部分
l=mid+1;
else
{
right = max(right, mid);
l=mid+1;
}
}
// printf("right = %d\n",right);
if(left != inf)
ans += right - left + 1;
}
cout<<ans<<endl;
return 0;
}