洛谷P3871 [TJOI2010]中位數(splay)
阿新 • • 發佈:2018-07-04
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] intfa[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)