Codeforces 689D Friends and Subsequences(二分+RMQ)

题意:给你两个数列a,b,然后问你有多少个区间 [l,r] ,使得

maxi=lrai=mini=lrbi

题解:原本想的是两个数列都单调栈处理,但是这样的话很复杂,首先是区间特别多,容易超时,然后是区间有重复,这个也很难处理。
所以我们应该转变思路,首先需要观察到一个性质,
maxi=lraimini=lrbimaxi=lr+1aimini=lr+1bi
这个是必然的把, 因为随着区间的增大,最大值会单调增,最小值会单调减,所以相减就是单调的。
这样我们就可以枚举左端点,然后去二分找右端点,找到那段能让 maxmin=0 的区间,这用两次二分就行了,然后查询区间最大最小值的时候,如果用线段树,复杂度是 O(nlog2n) ,如果用RMQ预处理的话,就能做到复杂度是 O(nlogn) ,枚举二分rmq这种套路,很不错,需要掌握


代码:

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;
#define   MAX           200005
#define   MAXN          6005
#define   maxnode       15
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
//const double inf   = 1e18;
const double eps   = 1e-8;
const LL    mod    = 1e9+7;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
    char c;
    while((c=getchar())<'0' || c>'9');
    x=c-'0';
    while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
 }
/*****************************************************/

int a[MAX],b[MAX];
int aa[MAX][25],bb[MAX][25];
int n;
void rmq_inita(){
    for(int i=0;i<n;i++) aa[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++){
        for(int i=0;i+(1<<j)-1<n;i++){
            aa[i][j]=max(aa[i][j-1],aa[i+(1<<(j-1))][j-1]);
        }
    }
}

void rmq_initb(){
    for(int i=0;i<n;i++) bb[i][0]=b[i];
    for(int j=1;(1<<j)<=n;j++){
        for(int i=0;i+(1<<j)-1<n;i++){
            bb[i][j]=min(bb[i][j-1],bb[i+(1<<(j-1))][j-1]);
        }
    }
}

int rmqa(int L,int R){
    int k=0;
    while((1<<(k+1))<=R-L+1) k++;
    return max(aa[L][k],aa[R-(1<<k)+1][k]);
}

int rmqb(int L,int R){
    int k=0;
    while((1<<(k+1))<=R-L+1) k++;
    return min(bb[L][k],bb[R-(1<<k)+1][k]);
}

int main(){
    while(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_inita();
        rmq_initb();
        LL ans=0;
        for(int i=0;i<n;i++){
            int l=i,r=n-1;
            while(l<=r){
                int mid=(l+r)/2;
                if(rmqa(i,mid)-rmqb(i,mid)<0) l=mid+1;
                else r=mid-1;
            }
            ans-=l;
            l=i,r=n-1;
            while(l<=r){
                int mid=(l+r)/2;
                if(rmqa(i,mid)-rmqb(i,mid)<=0) l=mid+1;
                else r=mid-1;
            }
            ans+=l;
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值