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

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

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

 

posted @ 2016-07-13 10:56  Shawn_Ji  阅读(298)  评论(0编辑  收藏  举报