您的位置:首页 > 其它

[BZOJ1901][ZJU2112]Dynamic Rankings

2016-02-01 10:30 465 查看

Zju2112 Dynamic Rankings

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。

Solution :

简单来说就是带修改的区间第k大.

不带修改的时候我们有一个经典做法,就是利用可持久化线段树,对于每一个位置都建立一棵保存[1,i]的线段树,利用区间减法得到区间信息.

其实我们可以知道,上面这种做法其实就是做了一个前缀和,那么这里我们就是要维护前缀和.

对于一个数列来说维护前缀和很简单,通过树状数组实现即可,其实对于线段树,可以看成是很多数列构成的,我们同样可以利用树状数组维护.

Code

#include <bits/stdc++.h>
using namespace std;

#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
typedef long long ll;
typedef pair<int, int> PII;
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}

const int N = 10000 + 10;
int n, m, top = 0, sz = 0, La, Lb, tot;
int num[N<<1], v
, A
, B
, K
, flag
;
int root
, lc[N*100], rc[N*100], sum[N*100], L
, R
;

inline int lowbit(int x) { return x&-x; }
inline void modify(int l, int r, int &x, int pos, int delta){
if (!x) x = ++sz; sum[x] += delta;
if (l == r) return;
int mid = l+r >> 1;
if (pos <= mid) modify(l, mid, lc[x], pos, delta);
else modify(mid+1, r, rc[x], pos, delta);
}
inline int query(int l, int r, int k){
if (l == r) return l;
int suml = 0, sumr = 0;
rep(i, 1, La) suml += sum[lc[L[i]]]; rep(i, 1, Lb) sumr += sum[lc[R[i]]];
int mid = (l+r)>>1;
if (k <= sumr - suml){
rep(i, 1, La) L[i] = lc[L[i]]; rep(i, 1, Lb) R[i] = lc[R[i]];
return query(l, mid, k);
}else{
rep(i, 1, La) L[i] = rc[L[i]]; rep(i, 1, Lb) R[i] = rc[R[i]];
return query(mid+1, r, k-(sumr-suml));
}
}
int main(){
read(n); read(m);
rep(i, 1, n) scanf("%d", &v[i]), num[++top] = v[i];
rep(i, 1, m){ char ch[3];
scanf("%s%d%d", ch, &A[i], &B[i]);
if (ch[0] == 'Q') { scanf("%d", &K[i]); flag[i] = 1; }
else num[++top] = B[i];
}
sort(num+1, num+1+top);
tot = unique(num+1, num+1+top)-num-1;

rep(i, 1, n){
int pos = upper_bound(num+1, num+1+tot, v[i])-num-1;
for (int j = pos; j <= n; j += lowbit(j)) modify(1, tot, root[j], pos, 1);
}

rep(i, 1, m) if (flag[i]){
La = Lb = 0; A[i]--;
for (int j = A[i]; j; j -= lowbit(j)) L[++La] = root[j];
for (int j = B[i]; j; j -= lowbit(j)) R[++Lb] = root[j];
printf("%d\n", num[query(1, tot, K[i])]);
}else{
int pos = upper_bound(num+1, num+1+tot, v[A[i]])-num-1;
for (int j = A[i]; j <= n; j += lowbit(j)) modify(1, tot, root[j], pos, -1);
v[A[i]] = B[i];
pos = upper_bound(num+1, num+1+tot, v[A[i]])-num-1;
for (int j = A[i]; j <= n; j += lowbit(j)) modify(1, tot, root[j], pos, 1);
}

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