HYSBZ1588 营业额统计【Splay】

转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4366582.html   ---by 墨染之樱花

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

【题目描述】逐个将数插入序列,定义最小波动为某个数与其之前的小于等于它的最大数与大于等于它的最小数和它的差值的较小值,求整个序列的最小波动之和。

【思路】经典的不能再经典的平衡树题目,可用于测试各种平衡树模板。今天刚写了一棵自己风格的splay,用这道题测试一下,156ms效果还不错

/* ***********************************************
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\n",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\n",sum);
    return 0;
}
代码君

 

posted @ 2015-03-25 19:08  墨染之樱花  阅读(425)  评论(0编辑  收藏  举报