【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
题解:
序列上的带修改的求区间第k小。树状数组套可持久化线段树。其实主席树的每一次Insert相当于一次线性变化(大雾),然后普通的主席树是按照上一个版本进行的变化,如果要修改的话那就用树状数组来维护这个线性变化,使得修改的复杂度从O(nlogn)降到了O((logn)^2)。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #ifdef WIN32 #define LL "%I64d" #else #define LL "%lld" #endif #ifdef CT #define debug(...) printf(__VA_ARGS__) #define setfile() #else #define debug(...) #define filename "" #define setfile() freopen(filename".in","r",stdin);freopen(filename".out","w",stdout); #endif #define R register #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++) #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b)) #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b)) #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0) char B[1<<15],*S=B,*T=B; inline int FastIn() { R char ch;R int cnt=0;R bool minus=0; while (ch=getc(),(ch < '0' || ch > '9') && ch != '-'); ch == '-' ?minus=1:cnt=ch-'0'; while (ch=getc(),ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0'; return minus?-cnt:cnt; } #define maxt 6200010 #define maxn 10010 const int oo = 1e9; int root[maxn], sum[maxt], ls[maxt], rs[maxt], tot, lcnt, rcnt, val[maxn], lr[maxn], rr[maxn]; #define lowbit(_x) ((_x) & -(_x)) int update (R int last, R int l, R int r, R int pre,R int c) { R int mid = l + r >> 1, nw = ++tot; sum[nw] = sum[last] + c; if (l == r) return nw; if (pre > mid) { ls[nw] = ls[last]; rs[nw] = update(rs[last], mid + 1, r, pre, c); } else { rs[nw] = rs[last]; ls[nw] = update(ls[last], l, mid, pre, c); } return nw; } inline int query(R int l, R int r, R int k) { while (l < r) { R int lsum = 0, rsum = 0, mid = l + r >> 1; for (R int i = 1; i <= lcnt; ++i) lsum += sum[ls[lr[i]]]; for (R int i = 1; i <= rcnt; ++i) rsum += sum[ls[rr[i]]]; if (rsum - lsum >= k) { for (R int i = 1; i <= lcnt; ++i) lr[i] = ls[lr[i]]; for (R int i = 1; i <= rcnt; ++i) rr[i] = ls[rr[i]]; r = mid; } else { for (R int i = 1; i <= lcnt; ++i) lr[i] = rs[lr[i]]; for (R int i = 1; i <= rcnt; ++i) rr[i] = rs[rr[i]]; l = mid + 1; k -= (rsum - lsum); } } return l; } int main() { // setfile(); R int n = FastIn(), q = FastIn(); for (R int i = 1; i <= n; ++i) { R int a = FastIn(); for (R int j = i; j <= n; j += lowbit(j)) root[j] = update(root[j], 0, oo, a, 1); val[i] = a; } for (R int i = 1; i <= q; ++i) { R char cmd = getc(); while (cmd!='Q'&&cmd!='C') cmd = getc(); R int a = FastIn(), b = FastIn(); if (cmd == 'Q') { R int k = FastIn(); lcnt = rcnt = 0; for (R int j = a - 1; j; j -= lowbit(j)) lr[++lcnt] = root[j]; for (R int j = b; j; j -= lowbit(j)) rr[++rcnt] = root[j]; printf("%d\n",query(0, oo, k) ); } else { for (R int j = a; j <= n; j += lowbit(j)) root[j] = update(root[j], 0, oo, val[a], -1); val[a] = b; for (R int j = a; j <= n; j += lowbit(j)) root[j] = update(root[j], 0, oo, b, 1); } } return 0; }