• bzoj 1588 [HNOI2002]营业额统计 splay tree


    http://www.lydsy.com/JudgeOnline/problem.php?id=1588

    splay tree 中的一些操作的说明:

    sc函数:
        inline void sc(int y,int x,int p) {
            如果p==0,则y是x的父亲,x是y的左儿子;
            如果p==1,则y是x的父亲,x是y的右儿子;
        }
    rot函数:
        inline void rot(int x) {
            y是x的父亲节点;
            如果x是y的左儿子,则w=0;如果x是y的右儿子,则w=1;
            设p是y的父亲;
            对x,y,p进行zig或zag操作;
        }
        效果:每次rot(x),x向根靠近一单位深度
    splay函数:
        void splay(int x,int rt) {
            不断zig、zag,使得最后x升到根的位置;
        }

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define inf (1<<29)
    const int maxn = 100010;
    int sum , splaysz;
    struct node {
        int p,chd[2],v;
        node (int P=0,int val=0) {
            chd[0]=chd[1]=0;
            p = P; v= val;
        }
    }tree[maxn];
    inline void sc(int y,int x,int p) { tree[y].chd[p]=x;tree[x].p=y; }
    inline void rot(int x) {
        int y = tree[x].p;
        int w = tree[y].chd[1] == x;
        sc(tree[y].p,x,tree[tree[y].p].chd[1]==y);
        sc(y,tree[x].chd[w^1],w);
        sc(x,y,w^1);
    }
    void splay(int x,int rt) {
        while(tree[x].p!=rt) {
            int y = tree[x].p;
            int w = tree[y].chd[1]==x;
            if(tree[y].p != rt && tree[tree[y].p].chd[w]==y) rot(y);
            rot(x);
        }
    }
    int insert(int val) {
        if(tree[0].chd[0]==0) {
            tree[++splaysz] = node(0,val);
            tree[0].chd[0] = splaysz;
            return 1;
        }
        int now = tree[0].chd[0];
        while(1) {
            if(val == tree[now].v) {
                return 0;
            }
            int w = val > tree[now].v;
            if(tree[now].chd[w]) now = tree[now].chd[w];
            else {
                tree[++splaysz] = node(now,val);
                tree[now].chd[w]= splaysz;
                splay(splaysz,0);
                return 1;
            }
        }
    }
    int get_pre() {
        int y = tree[0].chd[0];
        if(tree[y].chd[0] == 0) return -inf;
        y = tree[y].chd[0];
        while(tree[y].chd[1]) {
            y = tree[y].chd[1];
        }
        return tree[y].v;
    }
    int get_next() {
        int y = tree[0].chd[0];
        if(tree[y].chd[1] == 0) return inf;
        y = tree[y].chd[1];
        while(tree[y].chd[0]) {
            y = tree[y].chd[0];
        }
        return tree[y].v;
    }
    int main() {
        int n;
        while(~scanf("%d" , &n)) {
            sum = splaysz = 0;
            for(int i=1;i<=n;i++) {
                int num;
                if(scanf("%d",&num) == EOF) num = 0;
                if(i == 1) {
                    sum += num;
                    insert(num);
                    continue;
                }
                if(insert(num) == 0) continue;
                int a = get_next() - num;
                int b = num - get_pre();
                sum += min(a , b);
            }
            printf("%d
    " , sum);
        }
        return 0;
    }
    

      这份代码在bzoj上面跑了1076ms,可能是因为将zig,zag操作归约到了一起,以前的代码跑了152ms。

    以前的代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define inf (1<<29)
    const int maxn = 100100;
    int pre[maxn],key[maxn],ch[maxn][2],root,tot;//分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
    int n;
    //新建一个结点
    void new_node(int &r,int fa,int k) {
        r = ++tot;
        pre[r] = fa;
        key[r] = k;
        ch[r][0] = ch[r][1] = 0; //左右孩子为空
    }
    //旋转,kind为1为右旋,kind为0为左旋
    void rot(int x,int kind) {
        int y = pre[x];
        //类似SBT,要把其中一个分支先给父节点
        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;
    }
    //Splay调整,将根为r的子树调整为goal
    void splay(int r,int goal) {
        while(pre[r] != goal) {
            //父节点即是目标位置,goal为0表示,父节点就是根结点
            if(pre[pre[r]] == goal)
                rot(r,ch[pre[r]][0]==r);
            else {
                int y = pre[r];
                int kind = ch[pre[y]][0] == y;
                //两个方向不同,则先左旋再右旋
                if(ch[y][kind] == r) {
                    rot(r , !kind);
                    rot(r , kind);
                }
                //两个方向相同,相同方向连续两次
                else {
                    rot(y , kind);
                    rot(r , kind);
                }
            }
        }
        //更新根结点
        if(goal == 0) root = r;
    }
    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];
        }
        new_node(ch[r][k>key[r]] , r , k);
        splay(ch[r][k>key[r]] , 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() {
        while(~scanf("%d" , &n)) {
            root = tot = 0;
            int ans = 0;
            for(int i=1;i<=n;i++) {
                int num;
                if(scanf("%d",&num)==EOF) num = 0;
                if(i == 1) {
                    ans += num;
                    new_node(root , 0 , num);
                    continue;
                }
                if(insert(num) == 0) continue;
                int a = get_next(root);
                int b = get_pre(root);
                ans += min(a , b);
            }
            printf("%d
    " , ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    ASP.NET 错误
    linux下使用蓝牙设备【转】
    AIDL Android中的远程接口 [转]
    Handler理解
    Hid Report Descriptor
    Android kernel x86 编译方法
    Android Init Language
    DBUS 资源
    Analysing Bluetooth Keyboard Traffic with hcidump
    DBUS基础知识
  • 原文地址:https://www.cnblogs.com/tobec/p/3250092.html
Copyright © 2020-2023  润新知