1. 程式人生 > >洛谷P3871 [TJOI2010]中位數(splay)

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

badge 長度 const connect -s rank spl 操作 離散化

題目描述

給定一個由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: 復制
6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid
輸出樣例#1: 復制
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這道題的做法

#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; }

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