luoguP4755 Beautiful Pair (笛卡尔树+线段树合并+启发式合并)

新学了一下笛卡尔树,这道题是模板题,统计一下以 $x$ 为 lca 的点对就行.  

然后统计的话用线段树合并 + 启发式合并就行了. 

code: 

#include <bits/stdc++.h>  
#define N 100006   
#define ll long long    
#define lson s[x].ls  
#define rson s[x].rs  
#define MAX 1000000000   
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
ll an,ans[N];  
int n,tot;   
int val[N],L[N],R[N],sta[N],fa[N],RT[N],size[N];  
struct seg { int ls,rs,sum; }s[N*70];        
void dfs(int x) 
{
    size[x]=1;  
    if(L[x]) fa[L[x]]=x,dfs(L[x]),size[x]+=size[L[x]];  
    if(R[x]) fa[R[x]]=x,dfs(R[x]),size[x]+=size[R[x]];   
}                
void update(int &x,int l,int r,int p,int v) 
{
    if(!x) x=++tot;   
    s[x].sum+=v;  
    if(l==r) return;   
    int mid=(l+r)>>1;     
    if(p<=mid) update(lson,l,mid,p,v);   
    else update(rson,mid+1,r,p,v);    
}
int merge(int x,int y) 
{
    if(!x||!y) return x+y;    
    int now=++tot;    
    s[now].sum=s[x].sum+s[y].sum;   
    s[now].ls=merge(s[x].ls,s[y].ls);  
    s[now].rs=merge(s[x].rs,s[y].rs);  
    return now;   
}   
int query(int x,int l,int r,int L,int R) 
{
    if(!x) return 0;  
    if(l>=L&&r<=R) return s[x].sum;  
    int mid=(l+r)>>1,re=0;  
    if(L<=mid)  re+=query(lson,l,mid,L,R);  
    if(R>mid)   re+=query(rson,mid+1,r,L,R);  
    return re;    
}
int calc(int tmp,int ma,int y) 
{
    int R=ma/tmp;    
    return R<1?0:query(RT[y],1,MAX,1,R);    
}
void dfs2(int x,int ma,int y) 
{    
    an+=(ll)calc(val[x],ma,y);   
    if(L[x]) dfs2(L[x],ma,y);  
    if(R[x]) dfs2(R[x],ma,y);   
}
void solve(int x) 
{  
    an+=(ll)(val[x]==1);          
    if(L[x]) 
    {    
        solve(L[x]);        
        an+=(ll)calc(val[x],val[x],L[x]);    
    }
    if(R[x]) 
    {   
        solve(R[x]);   
        an+=(ll)calc(val[x],val[x],R[x]);    
    }
    if(L[x]&&R[x]) 
    {                      
        if(size[L[x]]<size[R[x]]) 
            dfs2(L[x],val[x],R[x]);   
        else 
            dfs2(R[x],val[x],L[x]);                           
    }  
    update(RT[x],1,MAX,val[x],1);  
    if(L[x]) RT[x]=merge(RT[x],RT[L[x]]);   
    if(R[x]) RT[x]=merge(RT[x],RT[R[x]]);   
}
int main() 
{ 
    // setIO("input");        
    scanf("%d",&n);   
    for(int i=1;i<=n;++i) 
        scanf("%d",&val[i]);  
    int top=0,rt=0;  
    for(int i=1;i<=n;++i) 
    {
        while(top&&val[i]>=val[sta[top]]) 
            L[i]=sta[top],--top;    
        if(top) R[sta[top]]=i;      
        sta[++top]=i;     
    }      
    dfs(rt=sta[1]);       
    solve(rt);           
    printf("%lld\n",an);  
    return 0;   
}

  

posted @ 2020-05-08 22:14  EM-LGH  阅读(224)  评论(0编辑  收藏  举报