您的位置:首页 > 其它

BZOJ 1901: Zju2112 Dynamic Rankings( 树状数组套主席树 )

2016-01-11 13:23 302 查看


裸的带修改主席树.. 之前用BIT套Splay( http://www.cnblogs.com/JSZX11556/p/4625552.html )A过..但是还是线段树好写...而且快(常数比平衡树小). 时空复杂度是O(Nlog(N)+Mlog^2(N))

-------------------------------------------------------------------------

#include<cstdio>#include<cstring>#include<algorithm>#include<cctype> using namespace std; #define H(v) (lower_bound(Hash, Hash + Hn, v) - Hash + 1) const int maxn = 10009; int N, Q;int seq[maxn];int Hash[maxn << 1], Hn;int Val, Pos; inline int read() { char c = getchar(); for(; !isdigit(c); c = getchar()); int ret = 0; for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0'; return ret;} struct Event { int l, r, v; Event(int _l = 0, int _r = 0, int _v = 0) : l(_l), r(_r), v(_v) { }} q[maxn]; void Init() { Hn = 0; N = read(), Q = read(); for(int i = 1; i <= N; i++) Hash[Hn++] = (seq[i] = read()); for(int i = 0; i < Q; i++) { char c = getchar(); for(; c != 'C' && c != 'Q'; c = getchar()); if(c == 'C') { int p = read(), v = read(); q[i] = Event(-1, p, v); Hash[Hn++] = v; } else { int l = read() - 1, r = read(); q[i] = Event(l, r, read()); } } sort(Hash, Hash + Hn); Hn = unique(Hash, Hash + Hn) - Hash;} struct Node { Node *lc, *rc; int v;} pool[5000000], *pt, *Null, *Root[maxn], *V[maxn]; void Init_sgt() { pt = pool; Null = pt++; Null->v = 0; Null->lc = Null->rc = Null;} Node* Modify(Node* t, int l, int r) { Node* o = pt++; o->v = t->v + Val; if(l != r) { int m = (l + r) >> 1; if(Pos <= m) { o->lc = Modify(t->lc, l, m); o->rc = t->rc; } else { o->lc = t->lc; o->rc = Modify(t->rc, m + 1, r); } } return o;} void Build() { Root[0] = Null; Val = 1; for(int i = 1; i <= N; i++) { Pos = seq[i] = H(seq[i]); Root[i] = Modify(Root[i - 1], 1, Hn); }} Node *L[20], *R[20];int Ln, Rn; void Work() { for(int i = 1; i <= Hn; i++) V[i] = Null; for(int i = 0; i < Q; i++) if(~q[i].l) { Ln = Rn = 0; for(int p = q[i].l; p; p -= p & -p) L[Ln++] = V[p]; for(int p = q[i].r; p; p -= p & -p) R[Rn++] = V[p]; Node *_L = Root[q[i].l], *_R = Root[q[i].r]; int l = 1, r = Hn; while(l < r) { int cnt = _R->lc->v - _L->lc->v, m = (l + r) >> 1; for(int j = 0; j < Ln; j++) cnt -= L[j]->lc->v; for(int j = 0; j < Rn; j++) cnt += R[j]->lc->v; if(cnt >= q[i].v) { _L = _L->lc; _R = _R->lc; for(int j = 0; j < Ln; j++) L[j] = L[j]->lc; for(int j = 0; j < Rn; j++) R[j] = R[j]->lc; r = m; } else { q[i].v -= cnt; _L = _L->rc; _R = _R->rc; for(int j = 0; j < Ln; j++) L[j] = L[j]->rc; for(int j = 0; j < Rn; j++) R[j] = R[j]->rc; l = m + 1; } } printf("%d\n", Hash[l - 1]); } else { Pos = seq[q[i].r], Val = -1; for(int p = q[i].r; p <= Hn; p += p & -p) V[p] = Modify(V[p], 1, Hn); Pos = seq[q[i].r] = H(q[i].v), Val = 1; for(int p = q[i].r; p <= Hn; p += p & -p) V[p] = Modify(V[p], 1, Hn); }} int main() { Init(); Init_sgt(); Build(); Work(); return 0;}------------------------------------------------------------------------

1901: Zju2112 Dynamic Rankings

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 5988 Solved: 2489
[Submit][Status][Discuss]

Description

给定一个含有n个数的序列a[1],a[2],a[3]……a
,程序必须回答这样的询问:对于给定的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
,这些数都小于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。

Input

对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

Output

Sample Input

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

Sample Output

3
6

HINT

20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。

Source

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: