一个初始为空的二叉搜索树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个数,对应添加当前元素后,每对节点之间的距离之和。

  先把树求出来。。具体的话就是每次添加元素之后,找到这个数的前驱后继,哪个有空位这个元素就在哪。随便写个什么数据结构。

  求节点的距离和的话。。我写了点分治,每次查找完往里面加点...查找啊去重啊什么的都是一样的套路...

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<bitset>
//#include<ctime>
#define ll long long
#define ull unsigned long long
#define ui unsigned int
#define d double
//#define ld long double
using namespace std;
const int maxn=,mxnode=maxn;
struct zs{int too,pre;}e[maxn<<];int tot,last[maxn];
int lc[mxnode],rc[mxnode],v[mxnode],rnd[mxnode],tt;int V,PRE,AFT,rt;bool u[maxn][];
int sz[maxn],mx[maxn],RT,POI,dis[maxn],st[maxn],top,mxdep[maxn];bool del[maxn];
int bel[maxn][],belson[maxn<<][],dist[maxn][],_sz[maxn],_sonsz[maxn<<];int ID;
ll _sum[maxn],_sonsum[maxn<<];
int a[maxn];
int i,j,k,n,m; int ra,fh;char rx;
inline int read(){
rx=getchar(),ra=,fh=;
while((rx<''||rx>'')&&rx!='-')rx=getchar();
if(rx=='-')fh=-,rx=getchar();
while(rx>=''&&rx<='')ra=ra*+rx-,rx=getchar();return ra*fh;
}
inline void maxs(int &a,int b){if(b>a)a=b;}
inline void lturn(int &x){int R=rc[x];rc[x]=lc[R],lc[R]=x,x=R;}
inline void rturn(int &x){int L=lc[x];lc[x]=rc[L],rc[L]=x,x=L;}
inline void insert(int &x){
if(!x){x=++tt,v[x]=V,rnd[x]=rand();return;}
if(V<v[x]){
insert(lc[x]);
if(rnd[lc[x]]<rnd[x])rturn(x);
}else{
insert(rc[x]);
if(rnd[rc[x]]<rnd[x])lturn(x);
}
}
void getpre(int x){
if(!x)return;
if(v[x]<V)PRE=v[x],getpre(rc[x]);else getpre(lc[x]);
}
void getaft(int x){
if(!x)return;
if(v[x]>V)AFT=v[x],getaft(lc[x]);else getaft(rc[x]);
}
inline void ins(int a,int b){
e[++tot].too=b,e[tot].pre=last[a],last[a]=tot;
e[++tot].too=a,e[tot].pre=last[b],last[b]=tot;
} void getrt(int x,int fa){
sz[x]=,mx[x]=;
for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa&&!del[e[i].too])
getrt(e[i].too,x),maxs(mx[x],sz[e[i].too]),sz[x]+=sz[e[i].too];
maxs(mx[x],POI-sz[x]);
if(mx[x]<mx[RT])RT=x;
}
void getpoi(int x,int fa){
dis[x]=dis[fa]+,st[++top]=x,sz[x]=;
for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa&&!del[e[i].too])
getpoi(e[i].too,x),sz[x]+=sz[e[i].too];
}
void work(int x,int dep){
int i,p;
RT=,getrt(x,),x=RT,mxdep[x]=dep,bel[x][dep]=x,dist[x][dep]=dis[x]=;
for(i=last[x];i;i=e[i].pre)if(!del[e[i].too]){
getpoi(e[i].too,x);ID++;
while(top)p=st[top--],bel[p][dep]=x,belson[p][dep]=ID,dist[p][dep]=dis[p];
}
del[x]=,sz[x]=-;
for(i=last[x];i;i=e[i].pre)if(!del[e[i].too])
POI=sz[e[i].too],work(e[i].too,dep+);
} int main(){
n=read();
for(i=;i<=n;i++){
a[i]=read();
if(i>){
PRE=AFT=,V=a[i],getpre(rt),getaft(rt),
insert(rt);
if(!PRE||!AFT)ins(PRE|AFT,a[i]),u[PRE|AFT][PRE>]=;
else if(!u[PRE][])u[PRE][]=,ins(PRE,a[i]);
else u[AFT][]=,ins(AFT,a[i]);
}else V=a[i],insert(rt);
}
// for(i=1;i<=n;i++)for(j=last[i];j;j=e[j].pre)printf("%d-->%d\n",i,e[j].too); mx[]=<<,POI=n,work(a[],);ll ans=;int fa,son,dis;
for(i=;i<=n;i++){
k=a[i]; ans+=_sum[k],_sz[k]++;
for(j=mxdep[k]-;j;j--)
fa=bel[k][j],son=belson[k][j],dis=dist[k][j],
ans+=1ll*dis*(_sz[fa]-_sonsz[son])+_sum[fa]-_sonsum[son],
_sz[fa]++,_sonsz[son]++,_sum[fa]+=dis,_sonsum[son]+=dis; printf("%lld\n",ans);
}
}

[51nod1297]管理二叉树的更多相关文章

  1. 51nod 1297 管理二叉树

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

  2. 51 nod 1297 管理二叉树

    原题链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1297 先是暴力加优化T了最后两个点…… 我还是来想想正解吧. ...

  3. 四则运算(Java) 陈志海 邓宇

    目录 Github项目地址 PSP表格 功能要求 题目 功能(已全部实现) 效能分析 设计实现过程 数值生成 算式生成 问题集生成 设计实现过程 代码说明 测试运行 代码覆盖率 项目小结 Github ...

  4. Netty源码解析 -- PoolChunk实现原理(jemalloc 3的算法)

    前面文章已经分享了Netty如何实现jemalloc 4算法管理内存. 本文主要分享Netty 4.1.52之前版本中,PoolChunk如何使用jemalloc 3算法管理内存. 感兴趣的同学可以对 ...

  5. 深入C#内存管理来分析值类型&引用类型,装箱&拆箱,堆栈几个概念组合之间的区别

    C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程 ...

  6. C语言实现二叉树-02版

    ---恢复内容开始--- 昨天,提交完我们的二叉树项目后,今天早上项目经理早早给我打电话: 他说,小伙子干的不错.但是为什么你上面的insert是recusive的呢? 你难道不知道万一数据量大啦!那 ...

  7. C++11 智能指针unique_ptr使用 -- 以排序二叉树为例

    用智能指针可以简化内存管理.以树为例,如果用普通指针,通常是在插入新节点时用new,在析构函数中调用delete:但有了unique_ptr类型的智能指针,就不需要在析构函数中delete了,因为当u ...

  8. linux内核分析之内存管理

    1.struct page /* Each physical page in the system has a struct page associated with * it to keep tra ...

  9. Android 内存管理(二)

    很多开发者都是从j2me或j2ee上过来的,对于内存的使用和理解并不是很到位,Android开发网本次给大家一些架构上的指导,防止出现豆腐渣工 程的出现.Android作为以Java语言为主的智能平台 ...

随机推荐

  1. 将自己的域名代理到Gitpages

    相信有很多程序员都有自己的域名,甚至很多人还有自己的服务器.去年我也买了半年的阿里云,在tomcat里面发war包,相当于一个正式的项目.但是很多前端程序员应该要求很简单,就是能将静态的html发布就 ...

  2. Mysql 锁基础

    本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/53 lock与latch 在数据库中,lock与latch都可以 ...

  3. js回到顶部------转载

    [1]锚点 使用锚点链接是一种简单的返回顶部的功能实现.该实现主要在页面顶部放置一个指定名称的锚点链接,然后在页面下方放置一个返回到该锚点的链接,用户点击该链接即可返回到该锚点所在的顶部位置 [注意] ...

  4. 解决NTPD漏洞,升级Ntpd版本

    关于解决漏洞的问题我就不详说了,主要就是升级版本.这里我们就直接简单记录下步骤: 1.升级 使用root用户登录系统进入到/home/guankong ,上传ntp-4.2.8p9-1.el6.x86 ...

  5. C++中double类型的数字如何保留三位小数点详解

    我们知道C语言中,如果要求输出结果保留三位小数,我们可以使用pritf()函数轻松的解决.但是C++的输出运算符<<并没有直接实现这个功能,怎么办呢?之前在找答案的过程中各路大神给出了千姿 ...

  6. PHP 购物车 php闭包 array_walk

    <?php class Cart { const PRICE_BUTTER = 1.00; const PRICE_MILK = 3.00; const PRICE_EGGS = 6.95; p ...

  7. 微信小程序一:微信小程序UI组件、开发框架、实用库

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/8079095.html 内容持续更新,维护中 邮箱 ...

  8. MySQL视图,触发器,事务,存储过程,函数

    create triggr triafterinsertcmdlog after insert on cmd_log FOR EACH ROW trigger_body .#NEW : 代表新的记录 ...

  9. MySQL字符串相关函数学习一

    这里总结一下常用的或者有可能用到的一些字符串内建函数 ① ASCII() :返回字符的ASCII码 如果输入的不是一个字符而是一个字符串呢?ascii()会只取第一个字符作为计算的参数,如: ② CH ...

  10. SQL基础学习_03_数据更新

    数据的插入 1. 基本INSERT语句     INSERT的基本语法为:     INSERT INTO  <表名> (列1, 列2, 列3,  -) VALUES (值1, 值2, 值 ...