ATB282H Min + Sum 学习笔记

ATB282H Min + Sum 学习笔记

Luogu Link

题意简述

给定序列 \(A,B\)。求有多少对 \((l,r)\) 满足 \(1\le l\le r\le n\),且

\[\sum_{i=l}^r B_i+\min_{i=l}^r A_i \le S \]

做法解析

显然极值分治,显然要启发式合并(枚举小的那个子树的缀,二分大的那个子树的缀能取到哪)。学过笛卡尔树就会。两个二分写完一个另一个复制过来改一改就行了。

代码实现

#include <bits/stdc++.h>
using namespace std;
namespace obasic{
    typedef long long lolo;
    template <typename _T>
    void readi(_T &x){
        _T k=1;x=0;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')k=-1;
        for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
        x*=k;return;
    }
    template <typename _T>
    void writi(_T x){
        if(x<0)putchar('-'),x=-x;
        if(x>9)writi(x/10);
        putchar(x%10+'0');
    }
};
using namespace obasic;
const int MaxN=2e5+5;
int N;lolo S,A[MaxN],B[MaxN],sum[MaxN],ans;
int stk[MaxN],ktp,ls[MaxN],rs[MaxN];
lolo getsum(int l,int r){return sum[r]-sum[l-1];}
lolo lbis(int u,int cl,int cr){
    lolo res=0,lim=S-A[u];
    for(int i=u;i>=cl;i--){
        lim-=B[i];if(lim<0)break;
        int lj=u,rj=cr,mj,sj;
        while(lj<=rj){
            mj=(lj+rj)>>1;
            if(getsum(u+1,mj)<=lim)sj=mj,lj=mj+1;
            else rj=mj-1;
        }
        res+=sj-u+1;
    }
    return res;
}
lolo rbis(int u,int cl,int cr){
    lolo res=0,lim=S-A[u];
    for(int i=u;i<=cr;i++){
        lim-=B[i];if(lim<0)break;
        int lj=cl,rj=u,mj,sj;
        while(lj<=rj){
            mj=(lj+rj)>>1;
            if(getsum(mj,u-1)<=lim)sj=mj,rj=mj-1;
            else lj=mj+1;
        }
        res+=u-sj+1;
    }
    return res;
}
lolo dfs(int u,int cl,int cr){
    if(cl==cr)return A[u]+B[u]<=S;
    lolo res=0;int lsiz=u-cl,rsiz=cr-u;
    if(lsiz<=rsiz)res+=lbis(u,cl,cr);
    else res+=rbis(u,cl,cr);
    if(ls[u])res+=dfs(ls[u],cl,u-1);
    if(rs[u])res+=dfs(rs[u],u+1,cr);
    return res;
}
int main(){
    readi(N),readi(S);
    for(int i=1;i<=N;i++)readi(A[i]);
    for(int i=1;i<=N;i++)readi(B[i]),sum[i]=sum[i-1]+B[i];
    for(int i=1;i<=N;i++){
        int k=ktp;
        while(k&&A[stk[k]]>A[i])k--;
        if(k)rs[stk[k]]=i;
        if(k<ktp)ls[i]=stk[k+1];
        stk[++k]=i,ktp=k;
    }
    ans=dfs(stk[1],1,N);writi(ans);
    return 0;
}

反思总结

极为板的笛卡尔树。蓝的总结。

posted @ 2025-02-21 10:53  矞龙OrinLoong  阅读(5)  评论(0)    收藏  举报