LGP4755 Beautiful Pair 学习笔记
LGP4755 Beautiful Pair 学习笔记
前言
复健。
题意简述
对于正整数列 \(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;
}
浙公网安备 33010602011771号