Friends and Subsequences(RMQ+二分||双端队列)

链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=121473#problem/D

                                         
                                      Friends and Subsequences
Time Limit:2000MS     Memory Limit:524288KB     64bit IO Format:%I64d & %I64u

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 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.

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]区间的情况下,有序列a的最大值等于序列b的最小值这种结果的区间的总数。

解析:

   这个要用到RMQ这个知识点,RMQ的预处理和查询有相应的模板,自己可以百度去了解记忆一下。

   利用区间特性进行二分,固定区间左端点(注意区间左端点和二分左端点不一样)

   确定最边缘左端点。

   若二分形成的最小值小于最大值,这个区间可以通过减小右端点而最大值可以再变小,最小值可以再变大,说明仍可以左移区间右端点

   若最小值大于最大值,则说明a区间中的数都小于b区间的最小值,只能右移区间左端点。

   确定最边缘右端点和上诉一样。

   若相等,则根据当前是求右边界最左端还是最右端进行相应移动。

   求出每一区间左端点对应的区间右端点的两个位置极值,作差,求和,求得结果。

注意:5-1<<1的结果是4<<1,即等于8。

         5-(1<<1)的结果是5-2,即等于3.

源代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 using namespace std;
 5 int fa[200010][20];
 6 int fb[200010][20];
 7 int RMQ(int L,int R,int x)
 8 {
 9     int k=log((R-L+1)*1.0)/log(2.0);
10     if(x==0)
11     return max(fa[L][k],fa[R+1-(1<<k)][k]);
12     else
13     return min(fb[L][k],fb[R+1-(1<<k)][k]);
14 }
15 int main()
16 {
17     int n;
18     scanf("%d",&n);
19     int a,b;
20     for(int i=0;i<n;i++)
21         scanf("%d",&fa[i][0]);
22     for(int i=0;i<n;i++)
23         scanf("%d",&fb[i][0]);
24     for(int j=1;(1<<j)<=n;j++)
25         for(int i=0;i+(1<<j)<=n;i++)
26         {
27             fa[i][j]=max(fa[i][j-1],fa[i+(1<<(j-1))][j-1]);
28             fb[i][j]=min(fb[i][j-1],fb[i+(1<<(j-1))][j-1]);
29         }
30     int l,r,ma,mb,st,en,mid;
31     long long sum=0;
32     for(int i=0;i<n;i++)     //固定查询的左端点
33     {
34         l=i;
35         st=-1;
36         r=n-1;
37         while(l<=r)     //二分求取最边缘左端点
38         {
39             mid=(l+r)/2;
40             ma=RMQ(i,mid,0);
41             mb=RMQ(i,mid,1);
42             if(ma>=mb)
43             {
44                 if(ma==mb) st=mid;
45                 r=mid-1;
46             }
47             else
48                 l=mid+1;
49         }
50         if(st==-1) continue;
51         l=i;
52         r=n-1;
53         en=-1;
54         while(l<=r)    //二分求取最边缘右端点
55         {
56             mid=(l+r)/2;
57             ma=RMQ(i,mid,0);
58             mb=RMQ(i,mid,1);
59 
60             if(ma>mb) r=mid-1;
61             else
62             {
63                 if(ma==mb) en=mid;
64                 l=mid+1;
65             }
66         }
67         sum+=(en-st+1);
68     }
69     printf("%lld
",sum);
70     return 0;
71 }

还有一种方法

利用双端队列(即两端都可以插入和删除),即deque

源代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[200010],b[200010];
 4 long long sum=0;
 5 int main()
 6 {
 7     int n;
 8     scanf("%d",&n);
 9     for(int i=1;i<=n;i++)
10         scanf("%d",&a[i]);
11     for(int i=1;i<=n;i++)
12         scanf("%d",&b[i]);
13     deque<int>x,y;
14     for(int i=1,j=1;i<=n;i++)
15     {
16         while(!x.empty()&&a[x.back()]<=a[i]) x.pop_back();
17         while(!y.empty()&&b[y.back()]>=b[i]) y.pop_back();
18         x.push_back(i);
19         y.push_back(i);
20         while(j<=i&&(a[x.front()]-b[y.front()]>0))
21         {
22             j++;
23             while(!x.empty()&&x.front()<j) x.pop_front();
24             while(!y.empty()&&y.front()<j) y.pop_front();
25         }
26         if(!x.empty()&&!y.empty()&&a[x.front()]==b[y.front()])
27             sum+=min(x.front(),y.front())-j+1;
28     }
29     printf("%lld
",sum);
30     return 0;
31 }
原文地址:https://www.cnblogs.com/q-c-y/p/5665024.html