[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 ", l); break; } } else r = mid; } if(!has) printf("%d ", l); } else { int p = read(), v = read(); update(1, n, 1, p, v); val[p] = v; } } return 0; }