TYVJ-1185 营业额统计 Splay

该题应该有很多的解法,想过用二分查找,但是排序操作的复杂度让我们伤不起。这里用Splay来实现是很方便的。首先插入一个点,即第一个点,然后再依次用二叉排序树方式插入当前点,再把该点旋转到根部(这样方便我们找前驱和后继,否则需要中序遍历整棵树来确定),再在存在前驱和后继的情况下寻找前驱和后继。接下来就很好办了。

代码如下:

#include <cstdlib>

#include <cstdio>

#include <cstring>

#include <algorithm>

#define L(x) tree[x].ch[0]

#define R(x) tree[x].ch[1]

#define INF 0x3ffffff

#define MAXN 33000

using namespace std;



int N, seq[MAXN], que[MAXN], front, rt;



struct Node

{

    int v, ch[2], fa;

    void New(int v, int fa) {

        this->v = v, this->fa = fa;

        ch[0] = ch[1] = 0;

    }

}tree[MAXN];



void init()

{

    for (int i = 0; i < MAXN; ++i) {

        que[i] = i;

    }

    rt = que[++front];

    tree[rt].New(seq[1], 0);

}



int insert(int &rt, int &num, int fa) // 引用仅仅为了速度考虑

{

    if (rt == 0) {

        // 说明这个节点是待填充的

        int x = que[++front];

        rt = x;

        tree[x].New(num, fa);

        return x;

    }

    if (num > tree[rt].v) { 

        return insert(R(rt), num, rt); 

    }

    else {

        return insert(L(rt), num, rt);

    }

}



void rotate(int x, int f)

{

    int y = tree[x].fa, z = tree[y].fa;

    tree[y].ch[!f] = tree[x].ch[f];

    tree[ tree[y].ch[!f] ].fa = y;

    tree[x].ch[f] = y;

    tree[y].fa = x;

    tree[x].fa = z;

    if (z) {

        tree[z].ch[ R(z) == y ] = x;

    }

}



void splay(int x, int obj)

{

    int y, z;

    while (tree[x].fa != obj) {

        y = tree[x].fa, z = tree[y].fa;

        if (z == obj) {

            rotate(x, L(y) == x);

        }

        else if (x == L(y) && y == L(z)) {

            rotate(y, 1), rotate(x, 1);

        }

        else if (x == R(y) && y == R(z)) {

            rotate(y, 0), rotate(x, 0);

        }

        else if (x == R(y) && y == L(z)) {

            rotate(x, 0), rotate(x, 1);

        }

        else {

            rotate(x, 1), rotate(x, 0);

        }

    }

    if (obj == 0) {

        rt = x;

    }

}



int findPre(int rt, int num)

{

    if (R(rt) == 0) {

        return tree[rt].v;

    }

    else {

        return findPre(R(rt), num);

    }

}



int findNext(int rt)

{

    if (L(rt) == 0) {

        return tree[rt].v;

    }

    else {

        return findNext(L(rt));

    }

}



int main()

{

    int pos, ans, pre, next, sum;

    while (scanf("%d", &N) == 1) {

        sum = 0;

        for (int i = 1; i <= N; ++i) {

            scanf("%d", &seq[i]);

        }

        init();

        if (N >= 1) {

            sum += seq[1];

        }

        for (int i = 1; i <= N; ++i) {

            ans = INF;

            pos = insert(rt, seq[i], tree[rt].fa);

            splay(pos, 0);  // 这个操作会将pos节点变成根节点

            if (L(rt)) {

                pre = findPre(L(rt), seq[i]);

                ans = abs(seq[i] - pre);

            }

            if (R(rt)) {

                next = findNext(R(rt));

                ans = min(abs(next - seq[i]), ans);

            }

            sum += ans;

        }

        printf("%d\n", sum);

    }

    return 0;

}

你可能感兴趣的:(play)