• 51nod 1297 管理二叉树


    一个初始为空的二叉搜索树T,以及1到N的一个排列P: {a1, a2, ..., aN}。我们向这个二叉搜索树T添加这些数,从a1开始, 接下来是 a2, ..., 以aN结束。在每一个添加操作后,输出T上每对节点之间的距离之和。

    例如:4 7 3 1 8 2 6 5。最终的二叉树为:
     
           4
         /  
        3      7   
      /      /  
     1      6     8
         /
       2  5
     
    节点两两之间的距离和 = 6+5+5+4+3+2+1+5+4+4+3+2+1+4+3+3+2+1+3+2+2+1+2+1+1+2+1+3 = 76
    Input
    第1行:1个数N。(1 <= N <= 100000)
    第2 - N + 1行:每行1个数,对应排列的元素。(1 <= ai <= N)
    Output
    输出共N行,每行1个数,对应添加当前元素后,每对节点之间的距离之和。

    用set维护一下空的左右孩子位置和已插入的点可以O(nlogn)建树

    然后就每加入 √(n) 个点重新树形dp一次,每加入一个点时和之前已加入但未dp的点间求距离,并计算和已dp的点对答案的贡献。
    总复杂度O(n√(n)logn)

    读入优化t了4个点,读入+输出优化t了1个点,fread+fwrite才a。。

    #include<stdio.h>
    #include<set>
    #include<cmath>
    const int N=100007;
    char buf[2000003],*ptr=buf,rbuf[1000003],*rptr=rbuf-1;
    inline int _(){
        int x=0,c=*++rptr;
        while(c<48)c=*++rptr;
        while(c>47)x=x*10+c-48,c=*++rptr;
        return x;
    }
    inline void _(long long x){
        static int stk[32],stp=0;
        if(!x)stk[stp++]=0;
        while(x)stk[stp++]=x%10,x/=10;
        while(stp)*ptr++=stk[--stp]+48;
        *ptr++=10;
    }
    int n,pv=0;
    std::set<int>le,re,in;
    int ch[N][2],xs[N],dep[N],fa[N],sz[N],pf[N],top[N];
    long long F1[N],F2[N],ans=0,ANS[N];
    int _sz[N],h[N],tp[N];
    inline int dis(int x,int y){
        int a=top[x],b=top[y],s=dep[x]+dep[y];
        while(a!=b){
            if(dep[a]<dep[b])y=fa[b],b=top[y];
            else x=fa[a],a=top[x];
        }
        s-=dep[dep[x]<dep[y]?x:y]<<1;
        return s;
    }
    void rebuild(){
        ans=0;
        for(int i=pv-1;~i;--i){
            int w=xs[i],lc=ch[w][0],rc=ch[w][1];
            h[w]=0;
            _sz[w]=1+_sz[lc]+_sz[rc];
            F1[w]=_sz[w]-1+F1[lc]+F1[rc];
        }
        for(int i=0;i<pv;++i){
            int w=xs[i],lc=ch[w][0],rc=ch[w][1],s=_sz[rc]-_sz[lc];
            F2[lc]=pv+s+F2[w]+F1[rc];
            F2[rc]=pv-s+F2[w]+F1[lc];
            F1[w]+=F2[w];
            ans+=F1[w];
        }
        ans>>=1;
    }
    int main(){
        rbuf[fread(rbuf,1,1000000,stdin)]=0;
        n=_();
        xs[0]=_();
        le.insert(xs[0]);
        re.insert(xs[0]);
        in.insert(xs[0]);
        for(int i=1;i<n;++i){
            int x=xs[i]=_();
            in.insert(x);
            auto it=le.upper_bound(x);
            if(it!=le.end()){
                auto it2=in.upper_bound(x);
                if(it2!=in.end()&&*it2==*it){
                    ch[fa[x]=*it][0]=x;
                    le.erase(it);
                    le.insert(x),re.insert(x);
                    continue;
                }
            }
            it=re.upper_bound(x);
            --it;
            ch[fa[x]=*it][1]=x;
            re.erase(it);
            le.insert(x),re.insert(x);
        }
        for(int i=0;i<n;++i){
            int w=xs[i];
            dep[w]=dep[fa[w]]+1;
        }
        for(int i=n-1;~i;--i){
            int w=xs[i];
            int sl=sz[ch[w][0]],sr=sz[ch[w][1]];
            sz[w]=1+sl+sr;
            pf[w]=ch[w][sl<sr];
        }
        for(int i=0;i<n;i++){
            int w=xs[i];
            if(!top[w])for(int u=w;u;u=pf[u])top[u]=w;
        }
        int B=std::sqrt(n)/1.2+1;
        for(int i=0;i<n;++i){
            int w=xs[i],f=fa[w];
            tp[w]=h[f]?tp[f]:f;
            h[w]=h[f]+1;
            ans+=h[w]*pv+F1[tp[w]];
            for(int j=pv;j<i;j++)ans+=dis(w,xs[j]);
            ANS[i]=ans;
            if(i%B==B-1){
                pv=i+1;
                rebuild();
            }
        }
        for(int i=0;i<n;++i)_(ANS[i]);
        fwrite(buf,1,ptr-buf,stdout);
        return 0;
    }
  • 相关阅读:
    python ratelimit使用
    团队怎样去做技术规划
    分词语义提取工具
    今日头条推荐系统
    要选择做有价值的事情
    总结与规划
    性能使用到极限
    流量运营
    Stanford CoreNLP使用需要注意的一点
    七年总结
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5785013.html
Copyright © 2020-2023  润新知