HYSBZ 1588 营业额统计 平衡二叉树模板

  题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1588

  题目描述: 给你N个数, 定义f(i) 为第i个数与i个数绝对值的最小值, 求f(1) + f(2) + f(3) + ....... + f(n)

  解题思路: 如何快速的找到与插入的值差的最小值, 就是左子树的最大值与右子树的最小值的绝对值差值的较小者。 一道平衡二叉树的模板题, 自己也复习了一下数据结构

  代码: 

/* ***********************************************
Author        :Kirisame_Marisa
blog          :http://www.cnblogs.com/KirisameMarisa/
Created Time  :2015年03月24日 星期二 20时45分12秒
File Name     :splay.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=100010;
#define eps 1e-10
#define zero(x) (fabs(x)<eps)
#define REP(X,N) for(int X=0;X<N;X++)
#define REP2(X,L,R) for(int X=L;X<=R;X++)
#define CLR(A,X) memset(A,X,sizeof(A))
#define PB(X) push_back(X)
#define MP(X,Y) make_pair(X,Y)
#define IT iterator
#define test puts("OK")
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VII;

const int null=-1;

struct node
{
    int par;
    int cld[2];    //0是左儿子,1是右儿子
    int key;
} ts[MAXN];
int root,cnt;

void init()
{
    root=null;
    cnt=0;
}

int newnode(int p,int k)
{
    ts[cnt].key=k;
    ts[cnt].par=p;
    ts[cnt].cld[0]=ts[cnt].cld[1]=null;
    return cnt++;
}

void rotate(int x,int k)    //k=0为左旋,k=1为右旋
{
    int y=ts[x].par;
    ts[y].cld[!k]=ts[x].cld[k];
    if(ts[x].cld[k]!=null)
        ts[ts[x].cld[k]].par=y;
    ts[x].par=ts[y].par;
    if(ts[y].par!=null)
    {
        if(y==ts[ts[y].par].cld[0])
            ts[ts[y].par].cld[0]=x;
        else
            ts[ts[y].par].cld[1]=x;
    }
    ts[y].par=x;
    ts[x].cld[k]=y;
}

void splay(int x,int S)   //伸展操作,将x旋转到目标节点,其中S为目标节点的parent
{
    while(ts[x].par!=S)
    {
        int p=ts[x].par;
        if(ts[p].par==S)
            rotate(x,ts[p].cld[0]==x);
        else
        {
            int d=(ts[ts[p].par].cld[0]==p);
            if(ts[p].cld[d]==x)
                rotate(x,!d),rotate(x,d);
            else
                rotate(p,d),rotate(x,d);
        }
    }
    if(S==-1)
        root=x;
}

bool insert(int x)
{
    if(root==null)
    {
        root=newnode(null,x);
        return 1;
    }
    int r=root,pre=null;
    while(r!=null)
    {
        if(ts[r].key==x)
        {
            splay(r,null);     //如果直接找到的话就不新建节点,直接splay
            return 0;
        }
        else
        {
            pre=r;
            r=ts[r].cld[ts[r].key<x];
        }
    }
    int &t=ts[pre].cld[ts[pre].key<x];
    t=newnode(pre,x);
    splay(t,null);
    return 1;
}

int getlow(int x)         //获取比它小的最大值。由于插入操作x已经被旋转到根节点,所以只要寻找左子树的最大值即可,下同
{
    int d=ts[root].cld[0];
    if(d==null)
        return INF;
    while(ts[d].cld[1]!=null)
        d=ts[d].cld[1];
    return x-ts[d].key;
}

int getup(int x)          //获取比它大的最小值
{
    int d=ts[root].cld[1];
    if(d==null)
        return INF;
    while(ts[d].cld[0]!=null)
        d=ts[d].cld[0];
    return ts[d].key-x;
}

void debug(int x)
{
    int l=ts[x].cld[0],r=ts[x].cld[1];
    if(l!=null)
        debug(l);
    printf("id:%2d key:%2d par:%2d lcd:%2d rcd:%2d
",x,ts[x].key,ts[x].par,l,r);
    if(r!=null)
        debug(r);
}

int main()
{
    //freopen("in","r",stdin);
    //freopen("out","w",stdout);
    init();
    int n,x,sum=0;
    scanf("%d%d",&n,&x);
    sum+=x;
    insert(x);
    REP(i,n-1)
    {
        x=0;
        scanf("%d",&x);
        bool temp=insert(x);
        if(temp)
            sum+=min(getlow(x),getup(x));
    }
    printf("%d
",sum);
    return 0;
}
模板

  思考: 模板转自http://www.cnblogs.com/KirisameMarisa/p/4366582.html, 感谢墨染之樱花......另外自己也看了看这个splay , 都是很基础的rotate和查询, 就当是回顾一下数据结构

  另外有一篇讲的很好的平衡二叉树文章, 放在这里, 提醒自己时刻进行学习.......前几天发烧了, 是烧的真的严重....但是也看明白了一些事情, 学到了不少东西, 我要努力变强, 这个学校我一分钟也不想待在这里!

原文地址:https://www.cnblogs.com/FriskyPuppy/p/7545158.html