[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
数据规模及约定
见“试题描述”
题解
打了一波线段树套 treap,相比于主席树套树状数组来说慢多了。。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
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 maxn 10005
#define maxnode 1280010
struct Node {
int v, r, siz;
Node() {}
Node(int _, int __): v(_), r(__) {}
} ns[maxnode];
int ToT, rt[maxn<<2], fa[maxnode], ch[2][maxnode];
void maintain(int o) {
ns[o].siz = 1;
for(int i = 0; i < 2; i++) if(ch[i][o])
ns[o].siz += ns[ch[i][o]].siz;
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(z) ch[ch[1][z]==y][z] = u;
if(ch[1][y] == u) swap(l, r);
fa[u] = z; fa[y] = u; fa[ch[r][u]] = y;
ch[l][y] = ch[r][u]; ch[r][u] = y;
maintain(y); maintain(u);
return ;
}
void insert(int& o, int v) {
if(!o) {
ns[o = ++ToT] = Node(v, rand());
return maintain(o);
}
bool d = v > ns[o].v;
insert(ch[d][o], v); fa[ch[d][o]] = o;
if(ns[ch[d][o]].r > ns[o].r) {
int t = ch[d][o];
rotate(t); o = t;
}
return maintain(o);
}
void del(int& o, int v) {
if(!o) return ;
if(ns[o].v == v) {
if(!ch[0][o] && !ch[1][o]) o = 0;
else if(!ch[0][o]) {
int t = ch[1][o]; fa[t] = fa[o]; o = t;
}
else if(!ch[1][o]) {
int t = ch[0][o]; fa[t] = fa[o]; o = t;
}
else {
bool d = ns[ch[1][o]].r > ns[ch[0][o]].r;
int t = ch[d][o]; rotate(t); o = t;
del(ch[d^1][o], v);
}
}
else {
bool d = v > ns[o].v;
del(ch[d][o], v);
}
return maintain(o);
}
int Find(int o, int v) {
if(!o) return 0;
int ls = ch[0][o] ? ns[ch[0][o]].siz : 0;
if(v >= ns[o].v) return ls + 1 + Find(ch[1][o], v);
return Find(ch[0][o], v);
}
int n, val[maxn];
void build(int L, int R, int o, int p) {
insert(rt[o], val[p]);
if(L == R) return ;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(p <= M) build(L, M, lc, p);
else build(M+1, R, rc, p);
return ;
}
void update(int L, int R, int o, int p, int v) {
del(rt[o], val[p]); insert(rt[o], v);
if(L == R) return ;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(p <= M) update(L, M, lc, p, v);
else update(M+1, R, rc, p, v);
return ;
}
int ql, qr;
int query(int L, int R, int o, int v) {
if(ql <= L && R <= qr) return Find(rt[o], v);
int M = L + R >> 1, lc = o << 1, rc = lc | 1, ans = 0;
if(ql <= M) ans += query(L, M, lc, v);
if(qr > M) ans += query(M+1, R, rc, v);
return ans;
}
int main() {
n = read(); int q = read();
for(int i = 1; i <= n; i++) val[i] = read(), build(1, n, 1, i);
while(q--) {
char tp[2]; scanf("%s", tp);
if(tp[0] == 'Q') {
ql = read(); qr = read(); int k = read();
int l = 0, r = (int)1e9; bool has = 0;
while(l < r) {
int mid = l + r >> 1;
if(query(1, n, 1, mid) < k) {
l = mid + 1;
if(query(1, n, 1, l) >= k){ has = 1; printf("%d\n", l); break; }
}
else r = mid;
}
if(!has) printf("%d\n", l);
}
else {
int p = read(), v = read();
update(1, n, 1, p, v);
val[p] = v;
}
}
return 0;
}