LibreOJ #106. 二逼平衡树

二次联通门 : LibreOJ #106. 二逼平衡树

/*
    LibreOJ #106. 二逼平衡树

    写了整整一下午
    1遍AC
    感人肺腑啊。。。

    我的做法比较中规中矩

    线段树套splay
    对于操作1没什么好说, 在线段树查询区间时查出排名

    对于操作2, 一开始没想太多
    在写完基础函数时突然意识到不好做
    在想不出好办法后看了题解, 得知了要用二分
    二分一下这个数, 二分出一个答案查排名
    然后找前驱即可

    操作3要在splay中删除再插入即可
    操作4, 5没什么可说的。。。。。。

    这个写法不太好。。
    既然封装了。。。就要考虑一下充分利用封装的好处啊。。 

*/
#include <cstdio>

#define Max 4000005
#define INF 1e9

void read (int &now)
{
    register char word = getchar ();
    bool temp = false;
    for (now = 0; word < ‘0‘ || word > ‘9‘; word = getchar ())
        if (word == ‘-‘)
            temp = true;
    for (; word >= ‘0‘ && word <= ‘9‘; now = now * 10 + word - ‘0‘, word = getchar ());
    if (temp)
        now = -now;
}

int data[Max];

struct S_D
{
    S_D *child[2], *father;

    int size, weigth;
    int key;

    S_D ()
    {
        this->child[0] = this->child[1] = NULL;
        this->father = NULL;

        this->size = this->weigth = 1;
        this->key = 0;
    }

    void Clear ()
    {
        this->child[0] = this->child[1] = NULL;
        this->father = NULL;
    }

    int Get_Pos ()
    {
        return this->father->child[1] == this;
    }

    inline void Updata ()
    {
        this->size = this->weigth;
        if (this->child[0])
            this->size += this->child[0]->size;
        if (this->child[1])
            this->size += this->child[1]->size;
    }
};

int Maxn = -INF;

inline int max (int a, int b)
{
    return a > b ? a : b;
}

inline int min (int a, int b)
{
    return a < b ? a : b;
}

struct X_D
{
    X_D *Left, *Right;

    int l, r;
    int Mid;

    X_D (int __l, int __r) : l (__l), r (__r)
    {
        Left = Right = NULL;
        Mid = __l + __r >> 1;
    }
};

int Answer;

class Splay_Tree_Type
{

    private :

        S_D *root[Max];

        void Rotate (S_D *now)
        {
            S_D *Father = now->father;
            int pos = now->Get_Pos () ^ 1;
            Father->child[pos ^ 1] = now->child[pos];
            if (now->child[pos])
                now->child[pos]->father = Father;
            if ((now->father = Father->father) != NULL)
                now->father->child[now->father->child[1] == Father] = now;

            Father->father = now;
            now->child[pos] = Father;

            Father->Updata ();
            now->Updata ();
        }

        void Splay (S_D *now)
        {
            for (S_D *Father; Father = now->father; this->Rotate (now))
                if (Father->father)
                    this->Rotate (now->Get_Pos () == Father->Get_Pos () ? Father : now);
        }

    public :

        void Insert (int pos, int x)
        {
            if (root[pos] == NULL)
            {
                root[pos] = new S_D ;
                root[pos]->key = x;
                return ;
            }
            S_D *now = root[pos], *Father;
            for (; ; Father = now, now = now->child[x > now->key])
            {
                if (now == NULL)
                {
                    now = new S_D;
                    now->father = Father;
                    now->key = x;
                    Father->child[x > Father->key] = now;
                    this->Splay (now);
                    root[pos] = now;
                    return ;
                }
                if (now->key == x)
                {
                    now->weigth ++;
                    this->Splay (now);
                    root[pos] = now;
                    return ;
                }
            }
        }

        int Find_Rank (int pos, int x)
        {
            S_D *now = root[pos];
            int Answer = 0;
            for (; ; )
            {
                if (now == NULL)
                    return Answer;
                if (now->key == x)
                    return (now->child[0] ? now->child[0]->size : 0) + Answer;
                else if (now->key < x)
                {
                    Answer += (now->child[0] ? now->child[0]->size : 0) + now->weigth;
                    now = now->child[1];
                }
                else if (now->key > x)
                    now = now->child[0];

            }
        }

        void Find (int pos, int x)
        {
            S_D *now;
            for (now = root[pos]; (now != NULL && x != now->key); now = now->child[x > now->key]);
            this->Splay (now);
            root[pos] = now;
            return ;
        }

        void Delete (int pos)
        {
            S_D *now = root[pos];
            if (now->weigth > 1)
            {
                now->weigth --;
                now->size --;
                return ;
            }
            if (now->child[0] == NULL && now->child[1] == NULL)
            {
                 root[pos] = NULL;
                 now->Clear ();
                 return ;
            }
            S_D *res;
            if (now->child[1] == NULL)
            {
                res = now;
                now->child[0]->father = NULL;
                root[pos] = now->child[0];
                res->Clear ();
                return ;
            }
            if (now->child[0] == NULL)
            {
                res = now;
                now->child[1]->father = NULL;
                root[pos] = now->child[1];
                res->Clear ();
                return ;
            }
            res = root[pos];
            S_D *res_pre = Find_Prefix_Pos (pos);
            this->Splay (res_pre);
            root[pos] = res_pre;
            root[pos]->child[1] = res->child[1];
            res->child[1]->father = root[pos];
            res->Clear ();
            root[pos]->Updata ();
            return;
        }

        S_D *Find_Prefix_Pos (int pos)
        {
            S_D *now = root[pos];
            for (now = now->child[0]; now->child[1]; now = now->child[1]);
            return now;
        }

        int Ask_Prefix (int pos, int x)
        {
            S_D *now = root[pos];
            for (; now;)
            {
                if (now->key < x)
                {
                    if (Answer < now->key)
                        Answer = now->key;
                    now = now->child[1];
                }
                else
                    now = now->child[0];
            }
            return Answer;
        }

        int Ask_Suffix (int pos, int x)
        {
            S_D *now = root[pos];
            for (; now; )
            {
                if (now->key > x)
                {
                    if (Answer > now->key)
                        Answer = now->key;
                    now = now->child[0];
                }
                else
                    now = now->child[1];
            }
            return Answer;
        }

};

Splay_Tree_Type Splay;

class Segment_Tree_Type
{

    private :

        X_D *Root;
        void __Build_ (X_D *&now, int l, int r)
        {
            now = new X_D (l, r);
            if (l == r)
                return ;
            __Build_ (now->Left, l, now->Mid);
            __Build_ (now->Right, now->Mid + 1, r);
        }

        void __Insert_ (X_D *&now, int pos, int x, int _in)
        {
            Splay.Insert (_in, x);
            if (now->l == now->r)
                return ;
            if (pos <= now->Mid)
                __Insert_ (now->Left, pos, x, _in << 1);
            else
                __Insert_ (now->Right, pos, x, _in << 1 | 1);
        }

        void __Query_Rank_ (X_D *&now, int l, int r, int k, int _in)
        {
            if (l <= now->l && now->r <= r)
            {
                Answer += Splay.Find_Rank (_in, k);
                return ;
            }
            if (l <= now->Mid)
                __Query_Rank_ (now->Left, l, r, k, _in << 1);
            if (now->Mid  < r)
                __Query_Rank_ (now->Right, l, r, k, _in << 1 | 1);
        }

        void __Change_ (X_D *&now, int pos, int x, int _in)
        {
            Splay.Find (_in, data[pos]);
            Splay.Delete (_in);
            Splay.Insert (_in, x);
            if (now->l == now->r)
                return ;
            if (pos <= now->Mid)
                __Change_ (now->Left, pos, x, _in << 1);
            else
                __Change_ (now->Right, pos, x, _in << 1 | 1);
        }

        void __Query_Prefix_ (X_D *&now, int l, int r, int x, int _in)
        {
            if (l <= now->l && now->r <= r)
            {
                Answer = max (Answer, Splay.Ask_Prefix (_in, x));
                return ;
            }
            if (l <= now->Mid)
                __Query_Prefix_ (now->Left, l, r, x, _in << 1);
            if (now->Mid < r)
                __Query_Prefix_ (now->Right, l, r, x, _in << 1 | 1);
        }

        void __Query_Suffix_ (X_D *&now, int l, int r, int x, int _in)
        {
            if (l <= now->l && now->r <= r)
            {
                Answer = min (Answer, Splay.Ask_Suffix (_in, x));
                return ;
            }
            if (l <= now->Mid)
                __Query_Suffix_ (now->Left, l, r, x, _in << 1);
            if (r > now->Mid)
                __Query_Suffix_ (now->Right, l, r, x, _in << 1 | 1);
        }

    public :

        void Build (int l, int r)
        {
            __Build_ (Root, l, r);
            return ;
        }

        void Insert (int pos, int x)
        {
            __Insert_ (Root, pos, x, 1);
            return ;
        }

        int Query_Suffix (int l, int r, int k)
        {
            Answer = INF;
            __Query_Suffix_ (Root, l, r, k, 1);
            return Answer;
        }

        int Query_kth_number (int l, int r, int x)
        {
            int L, R, Mid;
            for (L = 0, R = Maxn + 1, Mid; L != R; )
            {
                Mid = L + R >> 1;
                Answer = 0;
                this->Query_Rank (l, r, Mid);
                if (Answer < x)
                    L = Mid + 1;
                else
                    R = Mid;
            }
            return L - 1;
        }

        int Query_Rank (int l, int r, int k)
        {
            Answer = 0;
            __Query_Rank_(Root, l, r, k, 1);
            return Answer;
        }

        int Query_Prefix (int l, int r, int k)
        {
            Answer = 0;
            __Query_Prefix_ (Root, l, r, k, 1);
            return Answer;
        }

        void Change (int pos, int x)
        {
            __Change_ (Root, pos, x, 1);
            return ;
        }
};

Segment_Tree_Type Seg;

int main (int argc, char *argv[])
{
    int N, M;
    read (N);
    read (M);

    Seg.Build (1, N);
    for (int i = 1; i <= N; i ++)
    {
        read (data[i]);
        Maxn = max (data[i], Maxn);
        Seg.Insert (i, data[i]);
    }

    for (int type, x, y, z; M --; )
    {
        read (type);
        if (type == 1)
        {
            read (x);
            read (y);
            read (z);
            printf ("%d\n", Seg.Query_Rank (x, y, z) + 1);
        }
        else if (type == 2)
        {
            read (x);
            read (y);
            read (z);
            printf ("%d\n", Seg.Query_kth_number (x, y, z));
        }
        else if (type == 3)
        {
            read (x);
            read (z);
            Seg.Change (x, z);
            data[x] = z;
            Maxn = max (Maxn, x);
        }
        else if (type == 4)
        {
            read (x);
            read (y);
            read (z);
            printf ("%d\n", Seg.Query_Prefix (x, y, z));
        }
        else
        {
            read (x);
            read (y);
            read (z);
            printf ("%d\n", Seg.Query_Suffix (x, y, z));
        }
    }
    return 0;
}
时间: 2024-10-23 05:33:00

LibreOJ #106. 二逼平衡树的相关文章

BZOJ3196 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

[BZOJ 3196] 二逼平衡树 树状数组套主席树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3357  Solved: 1326[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为

BZOJ3196二逼平衡树【树套树】

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3776  Solved: 1483 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n

[Tyvj 1730] 二逼平衡树

先来一发题面QwQ [TYVJ1730]二逼平衡树 Time Limit:2 s   Memory Limit:512 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数

洛谷 P3380 【模板】二逼平衡树(树套树)

洛谷 P3380 [模板]二逼平衡树(树套树) 线段树套treap: 就是线段树每个节点放一个treap.建树复杂度应该是$n log n$,操作1,3,4,5的复杂度是$(log n)^2$,操作2的复杂度是$(log n)^3$. 操作3:找到线段树的对应叶子节点后找到要删除的值,在回溯的时候更新线段树相关的每一个节点(在treap中去掉要删除的值,再加入要加入的值) 操作1:将操作转化为统计(这个区间[l,r]内小于x的数的个数)+1.那么通过线段树将区间分解,然后对分解出的每一个区间对应

bzoj3196Tyvj 1730 二逼平衡树

bzoj3196Tyvj1730二逼平衡树 题意: 维护一个数列,操作:查询k在区间内的排名.查询区间内排名为k的值3.修改某一位上的数值.查询k在区间内的前驱(前驱定义为小于x,且最大的数).查询k在区间内的后继(后继定义为大于x,且最小的数) 题解: 线段树套treap,我写了一个星期QAQ第一.三个操作直接搞:第二个操作就二分那个值,然后查它在区间内的排名:第四.五个操作就当查询值≤(≥)当前节点就往左(右)走,用一个全局变量记往左(右)走时遍历过的最大(小)值.反思:本弱各种写挂,以前从

【BZOJ 3196】Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 842  Solved: 350 [Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,

BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )

这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<ios