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 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.
题意是两个数组a,b,每个数组给定n个数,求有多少个区间满足a数组的最大值等于b数组的最小值。
首先可以想到从区间[1,n]的最大值在不断增大,最小值在不断减少,也就是说明如果只维护最大或者最小值的话,这个维护的数组肯定是有序的。然后就是想办法维护这样一个数组,树状数组可以在非线性时间内完成数组的创建与查询,得到这样一个数组之后,我们可以枚举一个端点,然后去二分另一个端点,求出最大值==最小值的mid的最大值与最小值,然后相减再累加就是这样的区间的数量。如果是枚举左端点,维护树状数组的话,单点更新,很容易出现出现最大值之后将后面所有的值都覆盖的情况,这样我们就无法再去查找区间内的最值。此时,可以维护数组的后缀,枚举右端点,这样最值不会影响i之前的最值,因为只有遍历到maxi或者mini的时候才会更新后面的值,此时后面的值我们已经计算在内,所以并不会产生影响。
所以此题可以跑后缀,枚举左端点,二分右端点,树状数组维护区间最值并查询。
代码实现:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<cstdio>
#define ll long long
#define mset(a,x) memset(a,x,sizeof(a))
using namespace std;
const double PI=acos(-1);
const int inf=0x3f3f3f3f;
const double eps=1e-12;
const int maxn=1e6+5;
const int mod=1e9+7;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}
ll Fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n;n=n*n;}return r;}
ll upd(ll x,ll v){x=x+v>=mod?x+v-mod:x+v;return x;}
int minn[maxn],maxx[maxn],arr_a[maxn],arr_b[maxn],n;
void init()
{
for(int i=0;i<=n;i++)
maxx[i]=-(minn[i]=inf);
}
int lowbit(int k)
{
return k&(-k);
}
int query_max(int x)
{
int ans=-inf;
while(x)
{
ans=max(ans,maxx[x]);
x-=lowbit(x);
}
return ans;
}
int query_min(int x)
{
int ans=inf;
while(x)
{
ans=min(ans,minn[x]);
x-=lowbit(x);
}
return ans;
}
void add_max(int x,int y)
{
while(x<=n)
{
maxx[x]=max(maxx[x],y);
x+=lowbit(x);
}
}
void add_min(int x,int y)
{
while(x<=n)
{
minn[x]=min(minn[x],y);
x+=lowbit(x);
}
}
int main()
{
int i,j,k;
scanf("%d",&n);
init();
for(i=1;i<=n;i++)
scanf("%d",&arr_a[i]);
for(i=1;i<=n;i++)
scanf("%d",&arr_b[i]);
ll ans=0;
//最大值只会越来越大,最小值只会越来越小
for(i=n;i>0;i--)
{
add_max(i,arr_a[i]); //得到后缀最大值
add_min(i,arr_b[i]); //得到后缀最小值
int l=i,r=n+1,mid;
while(l<r) //后缀二分,即二分右端点
{
mid=(l+r)/2;
if(query_max(mid)>=query_min(mid)) //二分到最小的max==min的下标
r=mid;
else
l=mid+1;
}
int temp=l;
l=i;r=n+1;
while(l<r)
{
mid=(l+r)/2;
if(query_max(mid)>query_min(mid)) //二分到最大的max==min的下标
r=mid;
else
l=mid+1;
}
ans+=l-temp;
}
printf("%I64d\n",ans);
return 0;
}