码迷,mamicode.com
首页 > 其他好文 > 详细

51nod 1297 管理二叉树

时间:2016-08-18 19:34:49      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:

一个初始为空的二叉搜索树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;
}

 

51nod 1297 管理二叉树

标签:

原文地址:http://www.cnblogs.com/ccz181078/p/5785013.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!