zoj 3612 Median (splay)

题目大意:

添加和删除一个数,然后输出中位数。

简单的Splay   维护Splay上有多少个节点就可以了

#include <cstdio>
#include <iostream>
#define inf 1LL<<60
#define maxn 222222
#define keyTree (ch[ch[root][1]][0])

using namespace std;
typedef long long LL;
int S[maxn],que[maxn],ch[maxn][2],pre[maxn],siz[maxn];
int root,top1,top2;

LL val[maxn];

void New(int &x,int PRE,LL v)
{
    if(top2)x=S[--top2];
    else x=++top1;

    ch[x][0]=ch[x][1]=0;
    siz[x]=1;
    pre[x]=PRE;
    /*special*/
    val[x]=v;
}
void pushup(int x)/*special*/
{
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void pushdown(int x)
{

}

void Rotate(int x,int kind)
{
    int y=pre[x];
    pushdown(x);
    pushdown(y);
    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;
    pushup(y);
}
void Splay(int x,int goal)
{
    pushdown(x);
    while(pre[x]!=goal)
    {
        if(pre[pre[x]]==goal)
        Rotate(x,ch[pre[x]][0]==x);
        else
        {
            int y=pre[x];
            int kind=ch[pre[y]][0]==y;
            if(ch[y][kind]==x){
                Rotate(x,!kind);
                Rotate(x,kind);
            }
            else {
                Rotate(y,kind);
                Rotate(x,kind);
            }
        }
    }
    pushup(x);
    if(goal==0)root=x;
}
//把左数第k号节点放在goal下面
//调用了splay
void RotateTo(int k,int goal)
{
    int r=root;
    pushdown(r);
    while(siz[ch[r][0]]!=k)
    {
        if(k<siz[ch[r][0]])
        {
            r=ch[r][0];
        }
        else
        {
            k-=siz[ch[r][0]]+1;
            r=ch[r][1];
        }
        pushdown(r);
    }
    Splay(r,goal);
}
//删除节点x  并回收内存
void erase(int x)
{
    int y=pre[x];
    int head=0,tail=0;
    for(que[tail++]=x;head<tail;head++)
    {
        S[top2++]=que[head];
        if(ch[que[head]][0])que[tail++]=ch[que[head]][0];
        if(ch[que[head]][1])que[tail++]=ch[que[head]][1];
    }
    ch[y][ch[y][1]==x]=0;
    pushup(y);
}
//插入节点  键值为k

void init()/*special*/
{
    root=top1=top2=0;
    ch[0][0]=ch[0][1]=siz[0]=pre[0]=0;

    New(root,0,-inf);
    New(ch[root][1],root,inf);

    siz[root]=2;
}
int tot;

void insert(LL x,int pos)
{
    if(x<=val[pos])
    {
        if(ch[pos][0]==0)
        {
            Splay(pos,0);
            int l=siz[ch[root][0]];
            RotateTo(l-1,0);
            RotateTo(l,root);

            New(keyTree,ch[root][1],x);
        }
        else insert(x,ch[pos][0]);
    }
    else
    {
        if(ch[pos][1]==0)
        {
            Splay(pos,0);
            int l=siz[ch[root][0]];
            RotateTo(l,0);
            RotateTo(l+1,root);

            New(keyTree,ch[root][1],x);
        }
        else insert(x,ch[pos][1]);
    }
}

void print()
{
    if(tot&1)
    {
        RotateTo(tot/2+1,0);
        printf("%lld\n",val[root]);
    }
    else
    {
        RotateTo(tot/2,0);
        LL l=val[root];
        RotateTo(tot/2+1,0);
        LL r=val[root];

        if((l+r)%2)printf("%.1lf\n",(l+r)/2.0);
        else printf("%lld\n",(l+r)/2);
    }
}

bool remove(LL x,int pos)
{
    if(pos==0)
    {
        printf("Wrong!\n");
        return false;
    }
    if(x==val[pos])
    {
        Splay(pos,0);

        int l=siz[ch[root][0]];

        RotateTo(l-1,0);
        RotateTo(l+1,root);

        keyTree=0;

        return true;
    }
    else if(x<val[pos])
    {
        return remove(x,ch[pos][0]);
    }
    else return remove(x,ch[pos][1]);
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        tot=0;
        int m;
        scanf("%d",&m);
        while(m--)
        {
            char str[20];
            LL op;

            scanf("%s%lld",str,&op);

            if(str[0]==‘a‘)
            {
                insert(op,root);
                tot++;

                print();

            }
            else
            {

                if(remove(op,root))
                {
                    tot--;
                    if(tot)print();
                    else printf("Empty!\n");
                }
            }
        }
    }
    return 0;
}

zoj 3612 Median (splay)

时间: 2024-11-10 05:17:09

zoj 3612 Median (splay)的相关文章

URAL1306-Sequence Median(优先队列)

1306. Sequence Median Time limit: 1.0 second Memory limit: 1 MB Language limit: C, C++, Pascal Given a sequence of N nonnegative integers. Let's define the median of such sequence. If N is odd the median is the element with stands in the middle of th

ZOJ 3612 Median (multiset)

Median Time Limit: 5 Seconds      Memory Limit: 65536 KB The median of m numbers is after sorting them in order, the middle one number of them if m is even or the average number of the middle 2 numbers if m is odd. You have an empty number list at fi

zoj 1037 Gridland (简单)

Gridland Time Limit: 2 Seconds      Memory Limit: 65536 KB Background For years, computer scientists have been trying to find efficient solutions to different computing problems. For some of them efficient algorithms are already available, these are

URAL 1306 Sequence Median(优先队列)

题意:求一串数字里的中位数.内存为1M.每个数范围是0到2的31次方-1. 思路:很容易想到把数字全部读入,然后排序,但是会超内存.用计数排序但是数又太大.由于我们只需要第n/2.n/2+1大(n为偶数)或第(n+1)/2大(n为奇数).所以可以用优先队列来维护最值,这样只需要存一半元素(n/2+1个元素)就可以了. #include<cstdio> #include<algorithm> #include<queue> #define UL unsigned int

CF 295E Yaroslav and Points(Splay)

题目大意: 两个操作 1 id op  把id的位置+op 2 id op  查询在[id,op]之间的所有的数的差 思路: 关键是pushup函数. 自己退一下会发现,跟区间的总和,区间的节点个数有关. 比如如果左区间是 1 2 的话 右区间来一个 9 那么 就要加上 9-1+9-2 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include

P3391 【模板】文艺平衡树(Splay)新板子

P3391 [模板]文艺平衡树(Splay) 题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入输出格式 输入格式: 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, \cdots n-1,n)(1,2,?n−1,n) m表示翻转操作次数 接下来m行每行两个数 [l,r][l,

【BZOJ3506】排序机械臂(Splay)

[BZOJ3506]排序机械臂(Splay) 题面 神TMBZOJ没有题面,感谢SYC的题面 洛谷的题面也不错 题解 对于每次旋转的物体 显然可以预处理出来 现在只要模拟旋转操作就行了 至于在哪里放标记的问题 我只在第K大放会鬼.. 所以在Splay里面也放了一次(和LCT一样的) 然而我每次都把排到了正确位置的元素直接给删掉了... 所以跑的很慢很慢... #include<iostream> #include<cstdio> #include<cstdlib> #i

BZOJ 1251 序列终结者(Splay)

题目大意 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思.这道题目 就叫序列终结者吧.[问题描述] 给定一个长度为N的序列,每个序列的元素是一个整数(废话).要支持以下三种操作: 1. 将 [L, R] 这个区间内的所有数加上 V. 2. 将 [

HDU 4441 Queue Sequence(splay)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4441 题意:一个数列,三种操作:(1)插入:找到没在当前数列中的最小的正整数i,将其插在位置p之后,并将-i插入某个位置使得满足先进先出(i表示进,-i表示出),这个位置尽量靠右:(2)删除:删掉数字i以及-i:(3)询问:查询i和-i之间的数字的和. 思路:对于没在数列中的数字可以用一个set直接维护.i的插入是正常的splay操作.对于-i的插入,我们首先找到i之前有几个正数,比如有x个,那么-