ST表与二分 (CodeForces 689D-Friends and Subsequences)

 

Friends and Subsequences

题目链接:

http://acm.hust.edu.cn/vjudge/contest/121333#problem/H

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 max(al~ar)==min(bl~br) 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.

题意:

分别已知a b数组;
求有多少区间[l,r]满足max(al~ar)==min(bl~br);

分析:

首先建立ST表,便于计算任意区间的最大值和最小值。要想确定满足条件的区间个数,区间组合共(n-1)n/2 种,计算所有区间是显然超时的。

将区间的左端点l先固定住,右端点用二分求出满足条件的最小值first和最大值last,则对应于左端点为l的满足条件的区间个数为(last-first+1),遍历左端点 l

 

 

//RMQ与二分
#include <iostream>
#include <cmath>
using namespace std;

int dmax[200005][20];
int dmin[200005][20];
int a[200005];
int b[200005];
void rmq_st(int n)
{
    int i,j;
    for(i=0;i<n;i++)
        dmax[i][0]=a[i],dmin[i][0]=b[i];
    int m=(int)(log(1.0*n)/log(2.0));

    for(j=1;j<=m;j++)
    {
        for(i=0;i+(1<<j)-1<n;i++)
        {
            dmax[i][j]=max(dmax[i][j-1],dmax[i+(1<<(j-1))][j-1]);
            dmin[i][j]=min(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
        }
    }
}

int rmq_findmax(int l,int r)
{
  int k=(int)(log(1.0*(r-l+1))/log(2.0));

    return max(dmax[l][k],dmax[r-(1<<k)+1][k]);

}
int rmq_findmin(int l,int r)
{
    int k=(int)(log(1.0*(r-l+1))/log(2.0));

    return min(dmin[l][k],dmin[r-(1<<k)+1][k]);
}



int main()
{
      int n,i,j;
      cin>>n;
      for(i=0;i<n;i++)
          cin>>a[i];
      for(i=0;i<n;i++)
          cin>>b[i];
      rmq_st(n);
      long long ans=0;
      for(i=0;i<n;i++)
      {
           int l=i,r=n-1,mid,flag=0,x,y,first,last;
           //二分求右端点的最大值
          while(l<=r)
           {
               mid=(l+r)/2;
               x=rmq_findmax(i,mid);y=rmq_findmin(i,mid);
               if(x==y)
               {
                   flag=1;
                   last=mid;         
               }
               if(x>y)                //注意这是if而不是else if,目的是发现x==y时仍然向后查找,直到找到满足条件的最大值
                    r=mid-1;
               else l=mid+1;
           }
           //最终二分得到的结果的位置在r处
          if(flag)
           {
               l=i;
               r=n-1;
               while(l<=r)                     //二分求右端点的最小值
               {
                   mid=(l+r)/2;
                   x=rmq_findmax(i,mid);y=rmq_findmin(i,mid);
                   if(x<y)
                     l=mid+1;
                   else r=mid-1,first=mid;          //当x==y时,仍然向前查找,直到找到满足条件的最小值
               }
               //最终二分得到正确结果的位置是在l 处
               ans+=(last-first+1);
           }

      }
      cout<<ans<<endl;
    return 0;
}

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值