# 【题解】P4755 Beautiful Pair(启发式合并的思路+分治=启发式分治)

## 【题解】P4755 Beautiful Pair

upd: 之前一个first second烦了，现在AC了

## Luogu4755 Beautiful Pair($max$分治)

$max$分治意思就是分治的时候不好取中间数作为分治中心，要选择别的特殊数进行分治，此时可以利用启发式合并的思想做到外层一个$\log$

//@winlere
#include<iostream>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
#define lef l,mid,seg[pos].ls
#define rgt mid+1,r,seg[pos].rs
#define pp(x) seg[x].val=seg[seg[x].ls].val+seg[seg[x].rs].val
using namespace std;  typedef long long ll;   typedef const int& cint;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1e5+5;
pair<int,int> st[maxn][19];
int lg[maxn],n,data[maxn],sav[maxn],len;   ll ans;
inline pair<int,int> que(int l,int r){return max(st[l][lg[r-l]],st[r-(1<<lg[r-l])+1][lg[r-l]]);}
struct Chairseg{
struct E{
int ls,rs,val;
E(){ls=rs=val=0;} E(cint a,cint b,cint c){ls=a; rs=b; val=c;}
}seg[maxn*60];
int rt[maxn],cnt,n;
void build(int k,int val,int l,int r,int pos,int last){
if(l==r){seg[pos].val=seg[last].val+val;return;}
seg[pos]=seg[last];
if(k<=mid) seg[pos].ls=++cnt,build(k,val,lef,seg[last].ls);
if(k> mid) seg[pos].rs=++cnt,build(k,val,rgt,seg[last].rs);
pp(pos);
}
int que(int L,int R,int l,int r,int pos){
if(L>r||R<l||r<0) return 0;
if(L<=l&&r<=R) return seg[pos].val;
return que(L,R,lef)+que(L,R,rgt);
}
ll que(int L,int R,int l,int r){return que(l,r,1,n,rt[R])-que(l,r,1,n,rt[L-1]);}
inline void init(const int&n){this->n=n;}
}T;
inline int divd(const int&x){return upper_bound(sav+1,sav+len+1,x)-sav-1;}
void divd(int l,int r){
if(l>=r) return ans+=ll(l==r)*(data[l]==1),void();
const pair<int,int>&now=que(l,r);
if(now.second<mid)
for(int t=l;t<=now.second;++t)
ans=ans+T.que(now.second,r,1,divd(now.first/data[t]));
else
for(int t=now.second;t<=r;++t)
ans=ans+T.que(l,now.second,1,divd(now.first/data[t]));
divd(l,now.second-1); divd(now.second+1,r);
}
int main(){
n=qr();
for(int t=1;t<=n;++t) lg[t]=lg[t-1]+(1<<lg[t-1]<<1==t);
for(int t=1;t<=n;++t) st[t][0]=make_pair(data[t]=qr(),t),sav[t]=data[t];
for(int t=1;t<=lg[n];++t)
for(int i=1;i<=n;++i)
st[i][t]=max(st[i][t-1],st[min(i+(1<<t>>1),n)][t-1]);
sav[n+1]=1e9+1;
sort(sav+1,sav+n+2);
len=unique(sav+1,sav+n+2)-sav-1;
T.init(len);
for(int t=1;t<=n;++t) T.build(divd(data[t]),1,1,T.n,T.rt[t]=++T.cnt,T.rt[t-1]);
divd(1,n);
printf("%lld\n",ans);
return 0;
}


posted @ 2019-09-11 16:17  谁是鸽王  阅读(99)  评论(0编辑  收藏