[luogu4755]Beautiful Pair
luogu
第一次写最大值分治感觉有点丑
每次找到最大值mid,扫小的一边,主席树查大的一边小于等于(frac{a[mid]}{a[i]})的个数
复杂度(O(nlog^2n))
md主席树空间又挂了几次(修改次数*log值域)
#define ll long long
#include<bits/stdc++.h>
using namespace std;
const int _=1e5+5;
int re(){
int x=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
ll ans;
int n,m,tot;
int a[_],rt[_],lg[_],s[_*33],ls[_*33],rs[_*33],f[20][_];
void upd(int&x,int l,int r,int k){
s[++tot]=s[x]+1;ls[tot]=ls[x];rs[tot]=rs[x];
x=tot;if(l==r)return;int mid=l+r>>1;
if(k<=mid)upd(ls[x],l,mid,k);
else upd(rs[x],mid+1,r,k);
}
int qsum(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return s[x];
int mid=l+r>>1,res=0;
if(ql<=mid)res=qsum(ls[x],l,mid,ql,qr);
if(qr>mid)res+=qsum(rs[x],mid+1,r,ql,qr);
return res;
}
int qmax(int l,int r){
int k=lg[r-l+1],x=f[k][l],y=f[k][r-(1<<k)+1];
return a[x]>a[y]?x:y;
}
void solve(int l,int r){
int mid=qmax(l,r);
if(mid-l<r-mid){
for(int i=l;i<mid;i++){
ans+=qsum(rt[r],1,m,1,a[mid]/a[i]);
ans-=qsum(rt[mid-1],1,m,1,a[mid]/a[i]);
}
ans+=qsum(rt[r],1,m,1,1);
ans-=qsum(rt[mid],1,m,1,1);
}
else{
for(int i=mid+1;i<=r;i++){
ans+=qsum(rt[mid],1,m,1,a[mid]/a[i]);
ans-=qsum(rt[l-1],1,m,1,a[mid]/a[i]);
}
ans+=qsum(rt[mid-1],1,m,1,1);
ans-=qsum(rt[l-1],1,m,1,1);
}
if(l<mid-1)solve(l,mid-1);
if(mid+1<r)solve(mid+1,r);
}
int main(){
n=re();m=1e9;
for(int i=1;i<=n;i++)a[i]=re();
for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++){
ans+=(a[i]==1);
rt[i]=rt[i-1];f[0][i]=i;
upd(rt[i],1,m,a[i]);
}
for(int i=1;i<=lg[n];i++)
for(int j=1;j+(1<<i)-1<=n;j++){
int x=f[i-1][j],y=f[i-1][j+(1<<(i-1))];
f[i][j]=a[x]>a[y]?x:y;
}
solve(1,n);
printf("%lld
",ans);
return 0;
}