现在的位置: 首页 > 综合 > 正文

TYVJ-1185 营业额统计 Splay

2013年01月07日 ⁄ 综合 ⁄ 共 1783字 ⁄ 字号 评论关闭

该题应该有很多的解法,想过用二分查找,但是排序操作的复杂度让我们伤不起。这里用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;
}

抱歉!评论已关闭.