• bzoj 1588: [HNOI2002]营业额统计(splay入门)


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

    题解:这题如果用普通的bst的话是可以过时间差不多4s左右如果用splay的话是140ms。

    由于splay可以有序的插入,各种操作都不会改变中序遍历的结果,而且splay每次可以将插入的位置通过旋转到根的位置,那么这题就可以通过寻找根节点的前驱最大值和后继最小值找到答案而且非常快速。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #define inf 0X3f3f3f3f
    using namespace std;
    const int M = 1e5 + 10;
    int pre[M] , key[M] , ch[M][2] , root , tot;
    int n;
    void NewNode(int &r , int fa , int k) {
        r = ++tot;
        pre[r] = fa;
        key[r] = k;
        ch[r][0] = ch[r][1] = 0;
    }//初始化节点
    void Rotate(int x , int kind) {
        int y = pre[x];
        ch[y][!kind] = ch[x][kind];
        pre[ch[x][kind]] = y;
        if(pre[y]) ch[pre[y]][ch[pre[y]][1] == y] = x;
        pre[x] = pre[y];
        ch[x][kind] = y;
        pre[y] = x;
    }//旋转操作一般不改变
    void Splay(int r , int goal) {
        while(pre[r] != goal) {
            if(pre[pre[r]] == goal) Rotate(r , ch[pre[r]][0] == r);
            else {
                int y = pre[r];
                int kind = (ch[pre[y]][0] == y);
                if(ch[y][kind] == r) {
                    Rotate(r , !kind);
                    Rotate(r , kind);
                }
                else {
                    Rotate(y , kind);
                    Rotate(r , kind);
                }
            }
        }
        if(goal == 0) root = r;
    }//splay操作一般不改变就是将r点移到goal的子树
    void init(int n) {
        tot = root = 0;
        for(int i = 0 ; i <= n ; i++) {
            pre[i] = 0 , key[i] = 0 , ch[i][0] = ch[i][1] = 0;
        }
    }
    int Insert(int k) {
        int r = root;
        while(ch[r][key[r] <= k]) {
            if(key[r] == k) {
                Splay(r , 0);
                return 0;
            }//相同的点不插入。
            r = ch[r][key[r] <= k];
        }
        NewNode(ch[r][key[r] <= k] , r , k);
        Splay(ch[r][key[r] <= k] , 0);
        return 1;
    }//插入节点依据点的权值插左右子树
    int get_pre(int x) {
        int tmp = ch[x][0];
        if(tmp == 0) return inf;
        while(ch[tmp][1]) tmp = ch[tmp][1];
        return key[x] - key[tmp];
    }//寻找前驱最接近的点。
    int get_next(int x) {
        int tmp = ch[x][1];
        if(tmp == 0) return inf;
        while(ch[tmp][0]) tmp = ch[tmp][0];
        return key[tmp] - key[x];
    }//寻找后继最接近的点。
    int main() {
        int n , x , ans = 0;
        scanf("%d" , &n);
        scanf("%d" , &x);
        init(n);
        ans += x;
        Insert(x);
        n--;
        while(n--) {
            scanf("%d" , &x);
            if(Insert(x))
                ans += min(get_pre(root) , get_next(root));
        }
        printf("%d
    " , ans);
        return 0;
    }
  • 相关阅读:
    Codeforces 831 A Unimodal Array 模拟(我感觉我现在比任何时候都理解程序员就是专门写各种Bug这句话)
    HDU 1205 吃糖果 鸽巢原理
    UVA 12716 GCDXOR 数论
    HDU 6152 Friend-Graph Ramsey定理 组合数学
    UVA 10791 Minimum Sum LCM 数论
    DFS系列 POJ(自认为的讲解)
    HDU 5101
    gets,gets_s,fgets函数
    vector理解一波~~~
    BestCoder Round #74 (div.1) 1002Shortest Path(hdoj5636)
  • 原文地址:https://www.cnblogs.com/TnT2333333/p/7201124.html
Copyright © 2020-2023  润新知