1. 程式人生 > >BZOJ1901 Zju2112 Dynamic Rankings 【樹狀數組套主席樹】

BZOJ1901 Zju2112 Dynamic Rankings 【樹狀數組套主席樹】

i+1 for 一個 樹狀數組套主席樹 兩種 algorithm cnblogs ++ ()

題目

給定一個含有n個數的序列a[1],a[2],a[3]……a[n],程序必須回答這樣的詢問:對於給定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的數是多少(1≤k≤j-i+1),並且,你可以改變一些a[i]的值,改變後,程序還能針對改
變後的a繼續回答上面的問題。

輸入格式

第一行有兩個正整數n(1≤n≤10000),m(1≤m≤10000)。
分別表示序列的長度和指令的個數。
第二行有n個數,表示a[1],a[2]……a[n],這些數都小於10^9。
接下來的m行描述每條指令
每行的格式是下面兩種格式中的一種。
Q i j k 或者 C i t
Q i j k (i,j,k是數字,1≤i≤j≤n, 1≤k≤j-i+1)
表示詢問指令,詢問a[i],a[i+1]……a[j]中第k小的數。
C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改變成為t
m,n≤10000

輸出格式

對於每一次詢問,你都需要輸出他的答案,每一個輸出占單獨的一行。

輸入樣例

5 3

3 2 1 4 7

Q 1 4 3

C 2 6

Q 2 5 3

輸出樣例

3

6

題解

很裸的板
樹狀數組維護區間,主席樹維護樹狀數組每個節點權值信息
【debug弄得要死,調用時(1,tot)寫成了(l,r) QAQ】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define lbt(x) (x & -x) using namespace std; const int maxn = 10005,maxm = 10000005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57) {if (c == ‘-‘) flag = -1; c = getchar();} while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1
) + c - ‘0‘; c = getchar();} return out * flag; } int rt[maxn],A[maxn],B[2 * maxn],n,m,tot = 1,siz,N; int sum[maxm],ls[maxm],rs[maxm],a[2][20]; struct Que{int opt,l,r,k;}Q[maxn]; int getn(int x){ int l = 1,r = tot,mid; while (l <= r){ mid = l + r >> 1; if (B[mid] < x) l = mid + 1; else r = mid - 1; } return l; } void update(int& u,int l,int r,int pos,int v){ if (!u) u = ++siz; sum[u] += v; if (l == r) return; int mid = l + r >> 1; if (mid >= pos) update(ls[u],l,mid,pos,v); else update(rs[u],mid + 1,r,pos,v); } int query(int l,int r,int k){ if (l == r) return l; int mid = l + r >> 1,t = 0; for (int i = 1; i <= a[0][0]; i++) t += sum[ls[a[0][i]]]; for (int i = 1; i <= a[1][0]; i++) t -= sum[ls[a[1][i]]]; if (t >= k){ for (int i = 1; i <= a[0][0]; i++) a[0][i] = ls[a[0][i]]; for (int i = 1; i <= a[1][0]; i++) a[1][i] = ls[a[1][i]]; return query(l,mid,k); }else { for (int i = 1; i <= a[0][0]; i++) a[0][i] = rs[a[0][i]]; for (int i = 1; i <= a[1][0]; i++) a[1][i] = rs[a[1][i]]; return query(mid + 1,r,k - t); } } void add(int u,int x,int v){while (u <= n) update(rt[u],1,tot,x,v),u += lbt(u);} int solve(int l,int r,int k){ a[0][0] = a[1][0] = 0; for (int i = r; i; i -= lbt(i)) a[0][++a[0][0]] = rt[i]; for (int i = l - 1; i; i -= lbt(i)) a[1][++a[1][0]] = rt[i]; return query(1,tot,k); } int main(){ n = read(); m = read(); char c; REP(i,n) A[i] = B[++N] = read(); REP(i,m){ c = getchar(); while (c != ‘Q‘ && c != ‘C‘) c = getchar(); if (c == ‘Q‘) Q[i].opt = 0,Q[i].l = read(),Q[i].r = read(),Q[i].k = read(); else Q[i].opt = 1,Q[i].l = read(),Q[i].k = B[++N] = read(); } sort(B + 1,B + 1 + N); for (int i = 2; i <= N; i++) if (B[i] != B[tot]) B[++tot] = B[i]; REP(i,n) A[i] = getn(A[i]),add(i,A[i],1); REP(i,m){ if (!Q[i].opt) printf("%d\n",B[solve(Q[i].l,Q[i].r,Q[i].k)]); else{ Q[i].k = getn(Q[i].k); add(Q[i].l,A[Q[i].l],-1); A[Q[i].l] = Q[i].k; add(Q[i].l,A[Q[i].l],1); } } return 0; }

BZOJ1901 Zju2112 Dynamic Rankings 【樹狀數組套主席樹】