Tiger近期被公司升任为营业部经理。他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。

Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。

分析营业情况是一项相当复杂的工作。因为节假日,大减价或者是其它情况的时候,营业额会出现一定的波动,当然一定的波动是可以接受的,可是在某些时候营业额突变得非常高或是非常低。这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这样的情况:

该天的最小波动值 = min{|该天曾经某一天的营业额-该天营业额|}

当最小波动值越大时,就说明营业情况越不稳定。

而分析整个公司的从成立到如今营业情况是否稳定。仅仅须要把每一天的最小波动值加起来就能够了。你的任务就是编写一个程序帮助Tiger来计算这一个值。

第一天的最小波动值为第一天的营业额。

第一行为正整数n(n<=32767),表示该公司从成立一直到如今的天数,接下来的n行每行有一个正整数ai(ai<=1000000),表示第i天公司的营业额。

输出文件仅有一个正整数,即每天最小波动值之和,小于231

6

5

1

2

5

4

6

12

结果说明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12


思路:伸展树从下午開始看,曾经看过了,认为太麻烦了,然后数据结构老师讲过之后,我学明确了。考试都秒过。然后如今了才開始做题。

由于在数据结构实现中。本人比較喜欢数组替代指针。所以尼玛找了好久的模板才找到这个让自己认为非常爽又非常能理解的。其它都是指针来实现,代码又长。烦死了。

由于找了一下午加一晚上,实在找不到数组实现的伸展树了,就查了这个入门题的解题报告。最终让我发现了这个好代码,嘿嘿。

參考代码博客:http://blog.csdn.net/rowanhaoa/article/details/24436703

说明:伸展树是建立在排序二叉树上的。所以左子树全部的值都比根小。根又都比右子树全部的值小。

由于伸展树是平衡二叉树,所以具备平衡二叉树的特点。全部功能的平摊时间复杂度都是O(log n),所以在数据结构中用得非常爽,代码又是能够接受的复杂度和长度。

并且每一个结点也能够是区间,能够取代线段树,你说爽不爽。伸展树最大的长处是分裂和合并都是log n,所以比别的当然非常快,在处理非常多问题上自然有非常多长处。从此,爱上伸展树……


模板一:

这个伸展树的结点是用数据写的。是參照某个博客的,比較方便,只是有时候有点慢,由于是数组。所以debug不出来的几率比較高。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define INF 1000000007
#define maxn 100010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct splaytree //伸展树
{
    int pre[maxn];//前驱
    int key[maxn];//键值
    int ch[maxn][2];//左右孩子,0为左孩子,1为右孩子
    int root,tot;//根节点,节点数量
    splaytree()
    {
        tot=root=0;
        mem(ch,0);
        mem(pre,0);
        mem(key,0);
    }
    void newnode(int &r,int father,int k)
    {//在r位置,父亲为father。新建一个值点。
        r=++tot;
        pre[r]=father;
        key[r]=k;
        ch[r][0]=ch[r][1]=0;
    }
    void rotate(int x,int kind)//kind=1表示右旋。kind=0表示左旋
    {
        int y=pre[x];
        ch[y][!kind]=ch[x][kind];
        pre[ch[x][kind]]=y;
        ch[x][kind]=y;
        if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x;
        pre[x]=pre[y];
        pre[y]=x;
    }
    void splay(int x,int goal) //把x伸展到目标位置
    {
        while(pre[x]!=goal)
        {
            if(pre[pre[x]]==goal) rotate(x,ch[pre[x]][0]==x);
            else
            {
                int y=pre[x];
                int kind=ch[pre[y]][0]==y;
                if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind);
                else rotate(y,kind),rotate(x,kind);
            }
        }
        if(!goal) root=x;//把root更新成x
    }
    int insert(int x)//插入值x
    {
        int r=root;
        while(ch[r][key[r]<x])
        {
            if(key[r]==x) {splay(r,0);return 0;}
            r=ch[r][key[r]<x];
        }
        newnode(ch[r][x>key[r]],r,x);
        splay(ch[r][x>key[r]],0);
        return 1;
    }
    int find(int x)//查找键值为x的结点编号
    {
        int r=root;
        if(!r) return -INF;//树未建,未找到
        if(key[r]==x) return r;
        while(ch[r][x>key[r]])
        {
            r=ch[r][x>key[r]];
            if(key[r]==x) return r;
        }
        return -INF;//未找到
    }
    int get_pre(int x)//寻找节点x的前驱的值。未找到则返回INF
    {
        int r=ch[x][0];
        if(!r) return -INF;
        while(ch[r][1]) r=ch[r][1];
        return key[r];
    }
    int get_next(int x)
    {
        int r=ch[x][1];
        if(!r) return INF;
        while(ch[r][0]) r=ch[r][0];
        return key[r];
    }
};
int main()
{
    int sum=0,a,n;
    splaytree tree;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a);
        if(!i)
        {
            sum+=a;
            tree.newnode(tree.root,0,a);
            continue;
        }
        if(!tree.insert(a)) continue;
        //由于既然前面已经有a,那这天的相减为0,所以以下就不用继续了
        int x=tree.get_pre(tree.root);//由于insert之后根root即为当前a的
        int y=tree.get_next(tree.root);//故可从根查找
        sum+=min(a-x,y-a);
    }
    cout<<sum<<endl;
    return 0;
}

模板二:结构体结点

这个是參照百度百科上的代码写的,刚開始写的时候执行这题的数据出错,然后debug了好久,还以为代码中的splay和旋转错了。都已经放弃然后去找别的模板了。

可是后面还是输出当中过程的数据才知道错哪了。由于和数组的模板不一样,所以是自己传參的时候传错了,本来是传结点编号的,我传成值了。

为什么上面的模板不用。又找了这个呢。是由于我用上面的模板写一道题的时候严重超时,然后改又改不了了,然后自己又找了这个模板。比較好理解。数组类的模板写法太飘逸了,咱等寻常人一时难以接受,自己写的删除结点函数又不太会。所以仅仅能临时放弃数组的模板了。

用以下这个比較好理解。又好写,尽管代码是长了点。

这个模板不足之处就是insert的时候没有推断是否已经存在本值,size就直接加了。

这个在有些题面前改的东西就多了,上面数组模板就有优势了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,Sizeof(a))
#define INF 1000000007
#define maxn 100010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct splayNode
{
    int l, r, fa, val, size;
};
struct splaytree
{
    splayNode t[maxn];
    int root, tot;
    void create()
    {
        root = 1, tot = 2;
        t[1].val = -INF;
        t[2].val = INF;
        t[1].r = t[1].size = 2;
        t[2].fa = t[2].size = 1;
    }
    void dfs(int x)
    {
        if(x)
        {
            dfs(t[x].l);
            printf("结点%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d 键值为:%2d\n",x,t[x].l,t[x].r,t[x].fa,t[x].val);
            dfs(t[x].r);
        }
    }
    void debug()
    {
        printf("根为:%d\n",root);
        dfs(root);
    }
    void update(int x)
    {
        t[x].size=t[t[x].l].size+t[t[x].r].size+1;
    }
    void left(int x)
    {
        int fa = t[x].fa;
        t[x].fa = t[fa].fa;
        if (t[t[fa].fa].l==fa) t[t[fa].fa].l=x;
        if (t[t[fa].fa].r==fa) t[t[fa].fa].r=x;
        t[fa].fa = x;
        t[fa].r = t[x].l;
        t[t[x].l].fa = fa;
        t[x].l = fa;
        update(fa);
    }
    void right(int x)
    {
        int fa = t[x].fa;
        t[x].fa = t[fa].fa;
        if (t[t[fa].fa].l==fa) t[t[fa].fa].l=x;
        if (t[t[fa].fa].r==fa) t[t[fa].fa].r=x;
        t[fa].fa = x;
        t[fa].l = t[x].r;
        t[t[x].r].fa = fa;
        t[x].r = fa;
        update(fa);
    }
    void splay(int x, int FA = 0)
    {
        while (t[x].fa != FA)
        {
            int fa = t[x].fa;
            if (t[fa].fa == FA)
            {
                if (t[fa].l==x) right(x);
                else left(x);
            }
            else if (t[t[fa].fa].l==fa)
            {
                if(t[fa].l==x) right(fa),right(x);
                else left(x), right(x);
            }
            else if (t[fa].l==x) right(x),left(x);
            else left(fa), left(x);
        }
        update(x);
        if (!FA) root = x;
    }
    int lower_bound(int val)
    {
        int ans = 0, la = 0;
        for (int x = root; x;)
        {
            la = x;
            if (t[x].val>=val) ans=x,x=t[x].l;
            else x = t[x].r;
        }
        splay(la);
        return ans;
    }
    void insert(int val)
    {
        for (int x = root;;)
        {
            ++t[x].size;
            if (t[x].val >= val)
            {
                if (t[x].l) x = t[x].l;
                else
                {
                    t[x].l = ++tot;
                    t[tot].size = 1;
                    t[tot].fa = x;
                    t[tot].val = val;
                    splay(tot);
                    return;
                }
            }
            else if (t[x].r) x = t[x].r;
            else
            {
                t[x].r = ++tot;
                t[tot].size = 1;
                t[tot].fa = x;
                t[tot].val = val;
                splay(tot);
                return;
            }
        }
    }
    int get_lower(int a)
    {
        splay(a);
        for (a = t[a].l; t[a].r; a = t[a].r);
        return t[a].val;
    }
    int get_upper(int a)
    {
        splay(a);
        for (a = t[a].r; t[a].l; a = t[a].l);
        return t[a].val;
    }
    int get_rank(int a)
    {
        splay(a);
        return t[t[a].l].size;
    }
    void del(int l, int r)
    {
        l = get_lower(l);
        r = get_upper(r);
        splay(l);
        splay(r, l);
        t[r].l = 0;
        update(r);
        update(l);
    }
    int get_kth(int k)
    {
        ++k;
        for (int x=root;;)
        {
            if (t[t[x].l].size==k-1)
                return x;
            if (t[t[x].l].size>=k) x=t[x].l;
            else k-=t[t[x].l].size+1,x=t[x].r;
        }
    }
}tree;
map<int,int>Map;
int main()
{
    int n,a,sum=0;
    tree.create();
    cin>>n;
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a);
        //tree.debug();
        if(!i) sum+=a,tree.insert(a),Map[a]=1;
        else
        {
            if(Map[a]) continue;
            Map[a]=1;
            tree.insert(a);
            //tree.debug();
            int x=tree.get_lower(tree.root);
            int y=tree.get_upper(tree.root);
            //cout<<"+++"<<x<<' '<<y<<endl;
            sum+=min(a-x,y-a);
        }
    }
    cout<<sum<<endl;
    return 0;
}



posted on 2017-06-15 13:47  lxjshuju  阅读(184)  评论(0编辑  收藏  举报