Codeforces Round #361 (Div. 2) D (树状数组+二分)

D. Friends and Subsequences
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

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?

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.

Examples
input
6
1 2 3 2 1 4
6 7 1 2 3 2
output
2
input
3
3 3 3
1 1 1
output
0
Note

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值