LGP4755 Beautiful Pair 学习笔记

LGP4755 Beautiful Pair 学习笔记

\(\texttt{Luogu Link}\)

前言

复健。

题意简述

对于正整数列 \(A\),问有多少对 \((i,j)\) 满足:\(i\le j\)\(a_i\times a_j\le \max a[i,j]\)

\(n\le 10^5,a_i\le 10^9\)

做法解析

不带修的问所有区间,涉及到区间最大值,就差把笛卡尔树写你脸上了。

建树,然后对于每个结点为最大值的答案,启发式地,遍历其管辖的较小子树,准备用树状数组统计其较大子树,两只 \(\log\) 可以接受。什么你说值域 \(10^9\) 不能树状数组?别急我们可以离散化,对于每对 \(a_k\)\(a_i\)lower_bound 找到 \(a_j\) 最大的可接受数值再去查。当然由于我们的询问有下标和值域两个维度的限制,BiT 不能直接处理,所以我们把所有询问离线下来,差分一下,然后顺着下标一个一个加元素,一并解决询问。

总之这就是纯纯的板子,所以某个意义上这两段都是废话。作为古朝洛谷月赛的第四题还是合格的。现在,好好复健。虽然在 \(\texttt{Competitive Programming}\) 意义下我有没有健过也是个问题。

代码实现

真短。

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e5+5;
int N,A[MaxN],B[MaxN],nln;
int stk[MaxN],ktp,ls[MaxN],rs[MaxN];
lolo ans;
struct BinidTree{
    int t[MaxN],n;
    void init(int x){n=x,fill(t,t+n+1,0);}
    int lowbit(int x){return x&(-x);}
    void add(int p,int x){for(;p<=n;p+=lowbit(p))t[p]+=x;}
    int gts(int p){int res=0;for(;p;res+=t[p],p-=lowbit(p));return res;}
    int getsum(int l,int r){return gts(r)-gts(l-1);}
}BiT;
struct quer{int vl,vr,k;};
vector<quer> Q[MaxN];
void dfs(int u,int cl,int cr){
    if(!u)return;
    int lb=cl,rb=u,ld=u,rd=cr;
    if(cr-u<u-cl)swap(lb,ld),swap(rb,rd);
    for(int i=lb,tt;i<=rb;i++){
        tt=upper_bound(B+1,B+nln+1,B[A[u]]/B[A[i]])-B-1;
        if(tt)Q[ld-1].push_back({1,tt,-1}),Q[rd].push_back({1,tt,1});
    }
    dfs(ls[u],cl,u-1),dfs(rs[u],u+1,cr);
}
int main(){
    readi(N);BiT.init(N);
    for(int i=1;i<=N;i++)readi(A[i]),B[i]=A[i];
    for(int i=1,k;i<=N;i++){
        k=ktp;while(k&&A[stk[k]]<=A[i])ls[i]=stk[k--];
        rs[stk[k]]=i,stk[++k]=i,ktp=k;
    }
    sort(B+1,B+N+1),nln=unique(B+1,B+N+1)-(B+1);
    for(int i=1;i<=N;i++)A[i]=lower_bound(B+1,B+nln+1,A[i])-B;
    dfs(stk[1],1,N);
    for(int i=1;i<=N;i++){
        BiT.add(A[i],1);
        for(auto [vl,vr,k] : Q[i])ans+=BiT.getsum(vl,vr)*k;
    }
    writi(ans);
    return 0;
}
posted @ 2025-10-30 11:14  矞龙OrinLoong  阅读(3)  评论(0)    收藏  举报