zoukankan      html  css  js  c++  java
  • 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
    ",an);  
        return 0;   
    }
    

      

  • 相关阅读:
    nodejs+mongoose操作mongodb副本集实例
    创建mongodb副本集操作实例
    SpringBoot(二)Web整合开发
    SpringBoot(一)走进Springboot的世界
    Git(二)Git几个区的关系与Git和GitHub的关联
    Git(一)之基本操作详解
    HttpClient(二)HttpClient使用Ip代理与处理连接超时
    HttpClient(一)HttpClient抓取网页基本信息
    Jsoup(一)Jsoup详解(官方)
    MongoDB(一)环境搭建与初始配置
  • 原文地址:https://www.cnblogs.com/guangheli/p/12853403.html
Copyright © 2011-2022 走看看