前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >洛谷P3871 [TJOI2010]中位数(splay)

洛谷P3871 [TJOI2010]中位数(splay)

作者头像
attack
发布2018-07-05 10:43:07
4040
发布2018-07-05 10:43:07
举报

题目描述

给定一个由N个元素组成的整数序列,现在有两种操作:

1 add a

在该序列的最后添加一个整数a,组成长度为N + 1的整数序列

2 mid 输出当前序列的中位数

中位数是指将一个序列按照从小到大排序后处在中间位置的数。(若序列长度为偶数,则指处在中间位置的两个数中较小的那个)

例1:1 2 13 14 15 16 中位数为13

例2:1 3 5 7 10 11 17 中位数为7

例3:1 1 1 2 3 中位数为1

输入输出格式

输入格式:

第一行为初始序列长度N。第二行为N个整数,表示整数序列,数字之间用空格分隔。第三行为操作数M,即要进行M次操作。下面为M行,每行输入格式如题意所述。

输出格式:

对于每个mid操作输出中位数的值

输入输出样例

输入样例#1: 复制

代码语言:javascript
复制
6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid

输出样例#1: 复制

代码语言:javascript
复制
5
13

说明

对于30%的数据,1 ≤ N ≤ 10,000,0 ≤ M ≤ 1,000

对于100%的数据,1 ≤ N ≤ 100,000,0 ≤ M ≤ 10,000

序列中整数的绝对值不超过1,000,000,000,序列中的数可能有重复

每个测试点时限1秒

这题不是随便做么。。

口胡一下我能想到的做法吧,,

1.$M < 10000$的话vector暴力插入不知道能不能A,

2.直接用平衡树,我写的是splay,不想写代码的话可以用pb_ds里维护了siz域的红黑树

3.先离线,对权值离散化,然后用权值线段树查。

4.沿用https://www.luogu.org/problemnew/show/P1801这道题的做法

代码语言:javascript
复制
#include<cstdio>
using namespace std;
const int MAXN = 1e6 + 10;
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define root  ch[0][1]
int fa[MAXN], val[MAXN], rev[MAXN], siz[MAXN], ch[MAXN][2], tot = 0;
bool ident(int x) {
    return ch[fa[x]][0] == x ? 0 : 1;
}
void connect(int x, int _fa, int opt) {
    fa[x] = _fa, ch[fa[x]][opt] = x;
}
void update(int x) {
    siz[x] = siz[ls(x)] + siz[rs(x)] + rev[x];
}
void rotate(int x) {
    int Y = fa[x], R = fa[Y];
    int Yson = ident(x), Rson = ident(Y);
    int B = ch[x][Yson ^ 1];
    connect(B, Y, Yson);
    connect(x, R, Rson);
    connect(Y, x, Yson ^ 1);
    //tag 
    update(Y); update(x);
}
void splay(int x, int to) {
    to = fa[to]; 
    while(fa[x] != to) {
        int y = fa[x];
        if(fa[y] == to) rotate(x); 
        else if(ident(x) == ident(y)) rotate(y), rotate(x);
        else rotate(x), rotate(x);
    }
}
int NewNode(int _fa, int _val) {
    val[++tot] = _val;
    fa[tot] = _fa;
    siz[tot] = rev[tot] = 1;
    return tot;
}
void insert(int x) {
    if(!root) {root = NewNode(0, x); return ;}
    int now = root;
    while(now) {
        siz[now]++;
        if(val[now] == x) {rev[now]++; return ;}
        int nxt = val[now] < x;
        if(!ch[now][nxt]) {ch[now][nxt] = NewNode(now, x); splay(ch[now][nxt], root); return ;}
        now = ch[now][nxt];
    }
}
int ARank(int x) {
    int now = root;
    while(now) {
        //if(siz[now] == x) return val[now];
        int used = siz[now] - siz[rs(now)];
        if(x > siz[ls(now)] && x <= used) return val[now];
        if(used < x) x = x - used, now = ch[now][1];
        else now = ch[now][0];
    }
}
char opt[5];
int main() {
#ifdef WIN32
    freopen("a.in", "r", stdin);
#endif
    int N;
    scanf("%d", &N);
    for(int i = 1; i <= N; i++) {
        int x; scanf("%d", &x);
        insert(x);
    }
    int Q;
    scanf("%d", &Q);
    while(Q--) {
        scanf("%s", opt + 1);
        if(opt[1] == 'a') {
            int x;
            scanf("%d", &x);
            insert(x); N++;    
        }
        else 
            printf("%d\n", ARank(N / 2 + (N & 1)));
    }
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-07-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目描述
  • 输入输出格式
  • 输入输出样例
  • 说明
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档