http://codeforces.com/problemset/problem/689/D
题目大意:
给两个序列a,b 问有多少个相同的区间 在这个区间内a序列的最大值等于b序列的最小值
分析:
首先要解决区间问题 当然用RMQ就行 预处理O(n*log(n)) 询问O(1) 然后就是要找有多少个区间满足要求了
直接暴力显然不可以 分析一下区间特性 一个区间分以下三种情况
1、a的 max > b 的min 这时候应该减小这个区间 这样max才有可能变小,min才有可能变大
2、a的 max < b 的min 这时候应该增大这个区间 这样max才有可能变大,min才有可能变小
3、a的 max == b 的min 这时候就无所谓了 增大或者减小区间都可以 只要max还等于min就行
根据以上三条 我们可以采取固定左区间断点 二分找右区间端点 找一个a的 max == b 的min的最大端点 再找一个
a的 max == b 的min的最小端点 然后这个最大与最小端点之间的所有值都可以和左端点构成一个合法区间 然后累加
以下最大端点和最小端点的差就是答案
AC代码:
#include <bits/stdc++.h>
#define mset(a,x) memset(a,x,sizeof(a))
typedef long long LL;
using namespace std;
LL maxn[200005][25];
LL minn[200005][25];
LL a[200005],b[200005];
int n;
void init(){
for (int j=1;j<20;j++){
for (int i=1;i+(1<<j)<=n+1;i++){
maxn[i][j]=max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]);
minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
}
}
}
LL rmqmax(int l,int r){
int k=log(r-l+1)/log(2);
return max(maxn[l][k],maxn[r-(1<<k)+1][k]);
}
LL rmqmin(int l,int r){
int k=log(r-l+1)/log(2);
return min(minn[l][k],minn[r-(1<<k)+1][k]);
}
int main (){
while (scanf ("%d",&n)!=EOF){
mset(a,0);mset(b,0);mset(maxn,0);mset(minn,0);
for (int i=1;i<=n;i++) scanf ("%lld",&a[i]),maxn[i][0]=a[i];
for (int j=1;j<=n;j++) scanf ("%lld",&b[j]),minn[j][0]=b[j];
init();
int l,r;
LL sum=0;
for (int i=1;i<=n;i++){
int tl,tr;
tl=i,tr=n;
int indexr=0,indexl=0;
while (tl<=tr){// 求最大右端点
int mid=(tl+tr)/2;
LL tmax=rmqmax(i,mid);
LL tmin=rmqmin(i,mid);
if(tmin==tmax) tl=mid+1,indexr=mid;
else if (tmin>tmax) tl=mid+1;
else tr=mid-1;
}
if (indexr) {
tl=i,tr=n;
while (tl<=tr){// 求最小右端点
int mid=(tl+tr)/2;
LL tmax=rmqmax(i,mid);
LL tmin=rmqmin(i,mid);
if(tmin==tmax) tr=mid-1,indexl=mid;
else if (tmin>tmax) tl=mid+1;
else tr=mid-1;
}
sum+=indexr-indexl+1;
}
}
printf ("%lld\n",sum);
}
return 0;
}