JZOJ 【GDOI2017第三轮模拟day1】单旋

7 篇文章 0 订阅
5 篇文章 0 订阅

Description

H国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构。伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了H国的必修技能。有一天,邪恶的“卡”带着他的邪恶的“常数”来企图毁灭H国。“卡”给H国的人洗脑说,splay如果写成单旋的,将会更快。“卡”称“单旋splay”为“spaly”。虽说他说的很没道理,但还是有H国的人相信了,小H就是其中之一,spaly马上成为他的信仰。而H国的国王,自然不允许这样的风气蔓延,国王构造了一组数据,数据由m(不超过10^5)个操作构成,他知道这样的数据肯定打垮spaly,但是国王还有很多很多其他的事情要做,所以统计每个操作所需要的实际代价的任务就交给你啦。数据中的操作分为5种:
1. 插入操作:向当前非空spaly中插入一个关键码为key的新孤立节点。插入方法为,先让key和根比较,如果key比根小,则往左子树走,否则往右子树走,如此反复,直到某个时刻,key比当前子树根x小,而x的左子树为空,那就让key成为x的左孩子;或者key比当前子树根x大,而x的右子树为空,那就让key成为x的右孩子。该操作的代价为:插入后,key的深度。特别地,若树为空,则直接让新节点成为一个单个节点的树。(各节点关键码互不相等。对于“深度”的解释见末尾对spaly的描述。)
2. 单旋最小值: 将spaly中关键码最小的元素xmin单旋到根。操作代价为:单旋前xmin 的深度。(对于单旋操作的解释见末尾对spaly的描述。)
3. 单旋最大值: 将spaly中关键码最大的元素xmax单旋到根。操作代价为:单旋前xmax的深度。
4. 单旋删除最小值:先执行2号操作,然后把根删除。由于2号操作之后,根没有左子树,所以直接切断根和右子树的联系即可。(具体见样例解释)。操作代价同2号操作。
5. 单旋删除最大值:先执行3号操作,然后把根删除。操作代价同3号操作。

这里写图片描述
对于不是H国的人,你可能需要了解一些spaly的知识,才能完成国王的任务:
a. spaly是一棵二叉树,满足对于任意一个节点x,它如果有左孩子lx,那么lx的关键码小于x的关键码。如果有右孩子rx,那么rx的关键码大于x的关键码。

b. 一个节点在spaly的深度定义为:从根节点到该节点的路径上一共有多少个节点(包括自己)。
c. 单旋操作是对于一棵树上的节点x来说的。一开始,设f为x在树上的父亲。如果x为f的左孩子,那么执行zig(x)操作(如上图中,左边的树经过zig(x)变为了右边的树), 否则执行zag(x)操作(在上图中,将右边的树经过zag(f)就变成了左边的树)。每当执行一次zig(x)或者zag(x), x的深度减小1,如此反复,直到x为根。总之,单旋x就是通过反复执行zig和zag将x变为根。

Input

输入文件名为splay.in。
第一行单独一个正整数m (1 <= m <= 10^5)。
接下来m行,每行描述一个操作:首先是一个操作编号c(1<=c<=5),既问题描述中给出的5种操作中的编号,若c= 1,则再输入一个非负整数key,表示新插入节点的关键码。

Output

输出文件名为splay.out。
输出共m行,每行一个整数,第i行对应第i个输入的操作的代价。

Sample Input

5
1 2
1 1
1 3
4
5

Sample Output

1
2
2
2
2

Data Constraint

20%的数据满足:1 <= m <= 1000。
另外30%的数据满足:不存在4,5操作。
100%的数据满足:1<=m<=10^5;1<=key<=10^9。所有出现的关键码互不相同。任何一个非插入操作,一定保证树非空。在未执行任何操作之前,树为空。

分析

考虑一次插入了x,x的前驱为pre,后继为nxt,平衡树中排名相邻的两个点一定互为祖先关系,那么如果pre为nxt的祖先,x就插入到了nxt的左儿子,如果nxt为pre的祖先,x就插入到了pre的右儿子
考虑把最小值旋到根的操作,最小值没有左子树,最小值的右子树变成了最小值父亲的左子树,根变成了最小值的右儿子
把最大值旋到根同理
我很好奇 为什么我JZOJ上A了,放到BZOJ上却T了//

代码

#include <bits/stdc++.h>

#define N 1000005

using namespace std;

struct NOTE
{
    int son[2];
    int fa;
}t[N];

int root,size;

struct NODE
{
    int l,r;
    int dep;
    int lazy;
}T[N * 2];

int n,m;

int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

void build(int p,int l,int r)
{
    T[p].l = l;
    T[p].r = r;
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
}

int pos[N];

int find(int x)
{
    int l = 1, r = n,now;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (pos[mid] >= x)
            now = mid, r = mid - 1;
        else l = mid + 1;
    }
    return now;
}

void pushDown(int p)
{
    T[p * 2].lazy += T[p].lazy;
    T[p * 2 + 1].lazy += T[p].lazy;
    T[p * 2].dep += T[p].lazy;
    T[p * 2 + 1].dep += T[p].lazy;
    T[p].lazy = 0;
}

void change(int p,int x,int y)
{
    if (T[p].l == T[p].r)
    {
        T[p].dep = y;
        return;
    }
    if (T[p].lazy)
        pushDown(p);
    int mid = (T[p].l + T[p].r) >> 1;
    if (x <= mid)
        change(p * 2, x, y);
    else change(p * 2 + 1, x, y);
}

int query(int p,int x)
{
    if (!x)
        return 0;
    if (T[p].l == T[p].r)
        return T[p].dep;
    int mid = (T[p].l + T[p].r) >> 1;
    if (T[p].lazy)
        pushDown(p);
    if (x <= mid)
        query(p * 2,x);
    else query(p * 2 + 1,x);
}

void changeQ(int p,int l,int r,int x)
{
    if (l > r)
        return;
    if (l == T[p].l && r == T[p].r)
    {
        T[p].dep += x;
        T[p].lazy += x;
        return;
    }
    if (T[p].lazy)
        pushDown(p);
    int mid = (T[p].l + T[p].r) >> 1;
    if (r <= mid)
        changeQ(p * 2,l,r,x);
    else 
        if (l > mid)
            changeQ(p * 2 + 1,l,r,x);
        else
        {
            changeQ(p * 2,l,mid,x);
            changeQ(p * 2 + 1, mid + 1, r, x);
        }
}

void rotate(int x, int &k)
{
    int y = t[x].fa;
    int z = t[y].fa;
    int l,r;
    if (t[y].son[0] == x)
        l = 0;
    else l = 1;
    r = l ^ 1;
    if (y == k)
        k = x;
    else
    {
        if (t[z].son[0] == y)
            t[z].son[0] = x;
        else t[z].son[1] = x;
    }
    t[x].fa = z;
    t[y].fa = x;
    t[t[x].son[r]].fa = y;
    t[y].son[l] = t[x].son[r];
    t[x].son[r] = y;
}

void splay(int x,int &k)
{
    while (x != k)
    {
        int y = t[x].fa;
        int z = t[y].fa;
        if (y != k)
        {
            if (t[z].son[0] == y ^ t[y].son[0] == x)
                rotate(x,k);
            else rotate(y,k);
        }
        rotate(x,k);
    }
}

int getMin()
{
    int y = root;
    while (t[y].son[0])
        y = t[y].son[0];
    return y;
}

int getMax()
{
    int y = root;
    while (t[y].son[1])
        y = t[y].son[1];
    return y;
}

int Pre;

void getPre(int x,int k)
{
    if (!k)
        return;
    if (k < x)
    {
        Pre = k;
        getPre(x,t[k].son[1]);
    }
    else getPre(x,t[k].son[0]);
}

int Next;

void getNext(int x,int k)
{
    if (!k)
        return;
    if (k > x)
    {
        Next = k;
        getNext(x,t[k].son[0]);
    }
    else getNext(x,t[k].son[1]);
}

struct NODET
{
    int son[2];
    int fa;
}tr[N];

int trroot;

void insert(int x,int &k,int last)
{
    if (!k)
    {
        Pre = 0;
        Next = 0;
        k = x;
        t[x].fa = last;
        if (x < last)
        {
            Next = last;
            getPre(x,root);
        }
        else
        {
            Pre = last;
            getNext(x,root);
        }
        int dep1 = query(1,Next);
        int dep2 = query(1,Pre);
        if (dep1 > dep2)
        {
            tr[x].fa = Next;
            tr[Next].son[0] = x;
        }
        else
        {
            tr[x].fa = Pre;
            tr[Pre].son[1] = x;
        }
        printf("%d\n",max(dep1,dep2) + 1);
        change(1,x,max(dep1,dep2) + 1);
        splay(x,root);
        return;
    }
    if (x < k)
        insert(x,t[k].son[0],k);
    else insert(x,t[k].son[1],k);
}

void sloveMin()
{
    int x = getMin();
    printf("%d\n",query(1,x));
    int k = trroot;
    int y = tr[x].fa;
    int z = tr[x].son[1];
    if (k == x)
        return;
    if (y)
        changeQ(1,y,n,1);
    change(1,x,1);
    tr[y].son[0] = z;
    tr[z].fa = y;
    tr[x].fa = 0;
    tr[x].son[1] = k;
    tr[k].fa = x;
    trroot = x;
    splay(x,root);
}

void sloveMax()
{
    int x = getMax();
    printf("%d\n",query(1,x));
    int k = trroot;
    int y = tr[x].fa;
    int z = tr[x].son[0];
    if (k == x)
        return;
    if (y)
        changeQ(1,1,y,1);
    change(1,x,1);
    tr[y].son[1] = z;
    tr[z].fa = y;
    tr[x].fa = 0;
    tr[x].son[0] = k;
    tr[k].fa = x;
    trroot = x;
    splay(x,root);
}

void doMin()
{
    int x = getMin();
    printf("%d\n",query(1,x));
    int y = tr[x].fa;
    int z = tr[x].son[1];
    if (y)
        changeQ(1, x + 1, y - 1, -1);
    else
    {
        trroot = z;
        if (z)
            changeQ(1, x + 1, n, - 1);
    }
    tr[z].fa = y;
    tr[x].son[1] = 0;
    tr[y].son[0] = z;
    splay(x,root);
    root = t[x].son[1];
    t[x].son[1] = t[t[x].son[1]].fa = 0;
}

void doMax()
{
    int x = getMax();
    printf("%d\n",query(1,x));
    int y = tr[x].fa;
    int z = tr[x].son[0];
    if (y)
        changeQ(1, y + 1, x - 1, -1);
    else
    {
        trroot = z;
        if (z)
            changeQ(1, 1, x - 1, -1);
    }
    tr[z].fa = y;
    tr[x].son[0] = 0;
    tr[y].son[1] = z;
    splay(x,root);
    root = t[x].son[0];
    t[x].son[0] = t[t[x].son[0]].fa = 0;
}

int opt[N];
int num[N];

int main()
{
    freopen("splay.in","r",stdin);
    freopen("splay.out","w",stdout);
    m = read();
    for (int i = 1; i <= m; i++)
    {
        opt[i] = read();
        if (opt[i] == 1)
            pos[++n] = num[i] = read();
    }
    sort(pos + 1,pos + n + 1);
    for (int i = 1; i <= m; i++)
    {
        if (opt[i] == 1)
            num[i] = find(num[i]);
    }
    build(1,1,n);
    int tot = 0;
    for (int i = 1; i <= m; i++)
    {
        if (opt[i] == 1)
        {
            insert(num[i], root, 0);
            tot++;
            if (tot == 1)
                trroot = num[i];
        }
        if (opt[i] == 2)
            sloveMin();
        if (opt[i] == 3)
            sloveMax();
        if (opt[i] == 4)
            doMin(), tot--;
        if (opt[i] == 5)
            doMax(), tot--;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值