链接: http://codeforces.com/contest/689/problem/D
题意: 给你两个序列 你要求出有多少对 L ,R 使得A中的最大值等于B中的最小值。
思路: 先预处理出rmq 那么枚举每一个位置,找出这个位置的最小右端点和最大右端点就可以了。那么就用二分判断呗。因为对于每一个位置maxx 肯定是升序的,minn 肯定是降序的。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =2e5+5;
vector<int >A;
vector<int >B;
int n;
int mn[N][23];
int mx[N][23];
void init_rmq()
{
for(int i=0;i<n;i++) mx[i][0]=A[i];
for(int j=1;(1<<j)<=n;j++){
for(int i=0;i+(1<<j)-1<n;i++){
mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
}
}
for(int i=0;i<n;i++) mn[i][0]=B[i];
for(int j=1;(1<<j)<=n;j++){
for(int i=0;i+(1<<j)-1<n ;i++){
mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
}
}
}
int maxx(int l,int r)
{
int k=0;
while((1<<(k+1))<=r-l+1) k++;
return max(mx[l][k],mx[r-(1<<k)+1][k]);
}
int minn(int l,int r)
{
int k=0;
while((1<<(k+1))<=r-l+1) k++;
return min(mn[l][k],mn[r-(1<<k)+1][k]);
}
int jud(int l,int r,int num)
{
int x=maxx(l,r);
int y=minn(l,r);
if(x==y&&x==num) return 1;
return 0;
}
int solve(int le,int re)
{
int L,R;
L=-1; R=-1;
int l,r,mid,in=-1;
l=le; r=re;
while(l<=r)
{
mid=(l+r)>>1;
int v1 =maxx(le,mid),v2=minn(le,mid);
if(v1==v2){
L = mid;
r = mid-1;
}else if(v1<v2){
l = mid+1;
}else{
r = mid-1;
}
}
if(L==-1) return 0;
l=le; r=re;
while(l<=r)
{
mid=(l+r)>>1;
int v1 = maxx(le,mid),v2=minn(le,mid);
if(v1==v2){
R = mid;
l = mid+1;
}else if(v1<v2){
l = mid+1;
}else{
r = mid-1;
}
}
return R-L+1;
}
int main()
{
scanf("%d",&n);
int x;
for(int i=1;i<=n;i++){
scanf("%d",&x); A.push_back(x);
}
for(int i=1;i<=n;i++){
scanf("%d",&x); B.push_back(x);
}
init_rmq();
ll ans=0;
for(int i=0;i<n;i++){
ans+=1ll*solve(i,n-1);
}
printf("%lld\n",ans);
return 0;
}