D. Friends and Subsequences
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 exactlyn(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 numbersa1, a2, ..., an ( - 109 ≤ ai ≤ 109) — the sequence a.
The third line contains n integer numbersb1, 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 sincemax{2} = min{2}.
2.l = 4,r = 5 sincemax{2, 1} = min{2, 3}.
There are no occasions in the second sample case since Mike will answer3 to any query pair, but !Mike will always answer 1.
题意:查找两数组有区间最大与最小值相同的区间的个数。
思路:其中一个序列是区间求最大,最大值递非递减的。另一个求最小值则相反,是非递增的。所以两者必然有一个相同的值 的区间。因此可以枚举起点,二分最大与最小相同的对应区间右断点的左界与右界,(右界 - 左界 +1 ) 就是以枚举的当前点为左端点,区间最大值与最小值相同的区间个数。在查找区间最大与最小时需要用st表来查找,一开始用线段树第七组数据就超时了。
ST表其实也就是倍增思想。
详细见代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxn =3* 1e5+100;
typedef long long LL;
int A[maxn][20];
int B[maxn][20];
int len[maxn];
int n;
void init()
{
len[1]=0;
for(int i=2;i<maxn;i++)
{
len[i]=len[i-1];
if((1<<(len[i]+1)) == i) len[i]++;
}
}
void work(int &n)
{
int i,j;
for(i=n;i>=1;i--)
{
for(j=1;(i+(1<<j)-1) <=n;j++)
{
A[i][j]=max(A[i][j-1],A[i+(1<<(j-1))][j-1]);
B[i][j]=min(B[i][j-1],B[i+(1<<(j-1))][j-1]);
}
}
}
inline int query1(int &l,int &r)
{
return max(A[l][len[r-l+1]],A[r-(1<<len[r-l+1])+1][len[r-l+1]]);
}
inline int query2(int &l,int &r)
{
return min(B[l][len[r-l+1]],B[r-(1<<len[r-l+1])+1][len[r-l+1]]);
}
int main()
{
init();
int n;
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&A[i][0]);
for(i=1;i<=n;i++)
scanf("%d",&B[i][0]);
work(n);
LL ans=0;
for(i=1;i<=n;i++)
{
int lo=i-1;
int ub=n+1;
int mid;
while(ub-lo>1)
{
mid=(lo+ub)>>1;
if(query1(i,mid)-query2(i,mid)<0)
lo=mid;
else ub=mid;
}
if(ub>n) continue;
int a=ub;
lo=i-1;ub=n+1;
while(ub-lo>1)
{
mid=(lo+ub)>>1;
if(query1(i,mid)-query2(i,mid)>0)
ub=mid;
else lo=mid;
}
//cout<<lo<<" "<<a<<endl;
lo=min(lo,n);
if(lo>=a)
ans=ans+lo-a+1;
}
cout<<ans<<endl;
return 0;
}