[BZOJ1901]Zju2112 Dynamic Rankings
試題描述
給定一個含有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繼續回答上面的問題。你需要編一個這樣的程式,從輸入檔案中讀入序列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。
輸出
對于每一次詢問,你都需要輸出他的答案,每一個輸出占單獨的一行。
輸入示例
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
輸出示例
3
6
資料規模及約定
20%的資料中,m,n≤100; 40%的資料中,m,n≤1000; 100%的資料中,m,n≤10000。
題解
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxval 1000000000
#define maxn 10010
#define maxnode 4200010
int n;
int ToT, sumv[maxnode], lc[maxnode], rc[maxnode], recs[maxnode], rcnts;
int getsnode() {
if(rcnts) {
int o = recs[rcnts--];
sumv[o] = lc[o] = rc[o] = 0;
return o;
}
return ++ToT;
}
void update(int& o, int l, int r, int x, int v) {
if(!o) o = getsnode();
if(l == r) {
sumv[o] += v;
if(!sumv[o]) recs[++rcnts] = o, o = 0;
return ;
}
int mid = l + r >> 1;
if(x <= mid) update(lc[o], l, mid, x, v);
else update(rc[o], mid + 1, r, x, v);
sumv[o] = (lc[o] ? sumv[lc[o]] : 0) + (rc[o] ? sumv[rc[o]] : 0);
if(!sumv[o]) recs[++rcnts] = o, o = 0;
return ;
}
int rt[maxn<<2], No[maxn], cn;
void modify(int L, int R, int o, int p, int x, int v) {
update(rt[o], 0, maxval, x, v);
if(L == R) return ;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(p <= M) modify(L, M, lc, p, x, v);
else modify(M+1, R, rc, p, x, v);
return ;
}
void query(int L, int R, int o, int ql, int qr) {
if(ql <= L && R <= qr){ No[++cn] = rt[o]; return ; }
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(ql <= M) query(L, M, lc, ql, qr);
if(qr > M) query(M+1, R, rc, ql, qr);
return ;
}
int solve(int ql, int qr, int k) {
cn = 0; query(1, n, 1, ql, qr);
int l = 0, r = maxval;
while(l < r) {
int mid = l + r >> 1, sum = 0;
for(int i = 1; i <= cn; i++) if(No[i] && lc[No[i]]) sum += sumv[lc[No[i]]];
if(sum < k) {
k -= sum; l = mid + 1;
for(int i = 1; i <= cn; i++) if(No[i]) No[i] = rc[No[i]];
}
else {
r = mid;
for(int i = 1; i <= cn; i++) if(No[i]) No[i] = lc[No[i]];
}
}
return l;
}
int val[maxn];
int main() {
n = read(); int q = read();
for(int i = 1; i <= n; i++) val[i] = read(), modify(1, n, 1, i, val[i], 1);
char cmd[2];
while(q--) {
scanf("%s", cmd);
if(cmd[0] == 'Q') {
int ql = read(), qr = read(), k = read();
printf("%d\n", solve(ql, qr, k));
}
if(cmd[0] == 'C') {
int x = read(), v = read();
modify(1, n, 1, x, val[x], -1);
val[x] = v;
modify(1, n, 1, x, val[x], 1);
}
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxval 1000000000
#define maxn 10010
#define maxnode 4200010
int n, rt[maxn], val[maxn];
int ToT, sumv[maxnode], lc[maxnode], rc[maxnode];
void update(int& y, int x, int l, int r, int p, int v) {
sumv[y = ++ToT] = sumv[x] + v;
if(l == r) return ;
int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
if(p <= mid) update(lc[y], lc[x], l, mid, p, v);
else update(rc[y], rc[x], mid + 1, r, p, v);
return ;
}
int Rt[maxn], lrt[maxn], rrt[maxn], cl, cr;
void modify(int p, int x, int v) {
for(; p <= n; p += p & -p) update(Rt[p], Rt[p], 0, maxval, x, v);
return ;
}
void query(int ql, int qr) {
cl = cr = 0;
ql--; lrt[++cl] = rt[ql];
for(; ql; ql -= ql & -ql) lrt[++cl] = Rt[ql];
rrt[++cr] = rt[qr];
for(; qr; qr -= qr & -qr) rrt[++cr] = Rt[qr];
return ;
}
int solve(int ql, int qr, int k) {
query(ql, qr);
int l = 0, r = maxval;
while(l < r) {
int mid = l + r >> 1, sum = 0;
for(int i = 1; i <= cr; i++) if(rrt[i] && lc[rrt[i]]) sum += sumv[lc[rrt[i]]];
for(int i = 1; i <= cl; i++) if(lrt[i] && lc[lrt[i]]) sum -= sumv[lc[lrt[i]]];
if(sum < k) {
k -= sum; l = mid + 1;
for(int i = 1; i <= cl; i++) if(lrt[i]) lrt[i] = rc[lrt[i]];
for(int i = 1; i <= cr; i++) if(rrt[i]) rrt[i] = rc[rrt[i]];
}
else {
r = mid;
for(int i = 1; i <= cl; i++) if(lrt[i]) lrt[i] = lc[lrt[i]];
for(int i = 1; i <= cr; i++) if(rrt[i]) rrt[i] = lc[rrt[i]];
}
}
return l;
}
int main() {
n = read(); int q = read();
for(int i = 1; i <= n; i++) {
val[i] = read();
update(rt[i], rt[i-1], 0, maxval, val[i], 1);
}
char cmd[2];
while(q--) {
scanf("%s", cmd);
if(cmd[0] == 'Q') {
int ql = read(), qr = read(), k = read();
printf("%d\n", solve(ql, qr, k));
}
if(cmd[0] == 'C') {
int x = read(), v = read();
modify(x, val[x], -1);
modify(x, val[x] = v, 1);
}
}
return 0;
}