# bzoj 1901 动态区间第k大 （树套树）

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int Inf = 0x3f3f3f;
const int maxn = 51000;

inline int getnum() {
int ans = 0, f = 1;
char c = getchar();
if(c == '-') f = -1;
while(c < '0' || c > '9')	c = getchar();
while(c >= '0' && c <= '9') ans += c - '0', c = getchar();
return ans*f;
}

int n, m, tot;
int ch[maxn*20][2], size[maxn*20], p[maxn*20], cnt[maxn*20], key[maxn*20];
int c[maxn];

struct segment {
int root, l, r;
int get_ship(int x) {
return x == ch[p[x]][1];
}
void clear(int x) {
size[x] = cnt[x] = ch[x][1] = ch[x][0] = p[x] = key[x] = 0;
}
void up(int x) {
size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x];
}
void rotate(int x) {
int fa = p[x], gfa = p[p[x]], ship = get_ship(x);
ch[fa][ship] = ch[x][ship^1];	p[ch[fa][ship]] = fa;
ch[x][ship^1] = fa;	p[fa] = x;	p[x] = gfa;
if(gfa)
ch[gfa][fa == ch[gfa][1]] = x;
up(fa);  up(x);  up(gfa);
}
void splay(int x, int tar) {
for(int fa; (fa = p[x]) != tar; rotate(x))
if(p[fa] != tar)
rotate((get_ship(x) == get_ship(fa))? fa:x);
/*		int fa = p[x];
while(1) {
if(p[fa] != tar)
rotate((get_ship(x) == get_ship(fa))?fa:x);
rotate(x);
if((fa = p[x]) == tar)
break;
}
*/		if(tar == 0)
root = x;
}
void insert(int x) {
int now = root, fa = 0;
if(now == 0) {
tot++;	root = tot;	clear(tot);
key[tot] = x;
size[tot] = cnt[tot] = 1;
return;
}
while(1) {
if(key[now] == x) {
cnt[now]++;
size[now]++;	up(p[now]);
splay(now, 0);
return;
}
fa = now, now = ch[now][x > key[now]];
if(now == 0) {
now = ++tot;
clear(tot);
cnt[now] = size[now] = 1;
key[now] = x;	p[now] = fa;	ch[fa][x > key[fa]] = now;
up(fa);		splay(now, 0);
return;
}
}
}
int find_no(int x) {
int now = root;
while(1) {
if(x <= size[ch[now][0]])
now = ch[now][0];
else {
x -= size[ch[now][0]] + cnt[now];
if(x <= 0)
return key[now];
now = ch[now][1];
}
}
}//找到第x大的数字
int find_num(int x) {
int now = root, ans = 0;
while(1) {
if(now == 0)
return ans;
if(x < key[now])
now = ch[now][0];
else {
ans += (ch[now][0]?size[ch[now][0]]:0);
if(x == key[now]) {
splay(now, 0);
return ans;
}
ans += cnt[now];
now = ch[now][1];
}
}
}//找数字是第多少大
int pre() {
int now = ch[root][0];
while(ch[now][1])
now = ch[now][1];
return now;
}
int next() {
int now = ch[now][1];
while(ch[now][0])
now = ch[now][0];
return now;
}
void delate(int x) {
int no = find_num(x);
if(cnt[root] > 1) {
cnt[root]--; size[root]--;
return;
}
if(!ch[root][0] && !ch[root][1]) {
clear(root);	root = 0;
return;
}
if(!ch[root][0]) {
int oldroot = root;
root = ch[root][1];	p[root] = 0;
clear(oldroot);
return;
}
if(!ch[root][1]) {
int oldroot = root;
root = ch[root][0];	p[root] = 0;
clear(oldroot);
return;
}
int bigleft = pre(), oldroot = root;
splay(bigleft, 0);
ch[root][1] = ch[oldroot][1];
p[ch[root][1]] = root; clear(oldroot);
up(root);
return;
}
}a[maxn*4];

void build(int o, int l, int r) {
a[o].l = l, a[o].r = r;
for(int i = l; i <= r; i++)
a[o].insert(c[i]);
if(l == r)
return;
int mid = l + (r-l)/2;
build(o*2, l, mid);		build(o*2+1, mid+1, r);
}

void update(int o, int l, int k) {
a[o].delate(c[l]);
a[o].insert(k);
if(a[o].l == a[o].r)	return;
int mid = a[o].l + (a[o].r-a[o].l)/2;
if(mid >= l)
update(o*2, l, k);
else
update(o*2+1, l, k);
}//将第l个数字替换为k；

int sum = 0;

void find_rank(int o, int l, int r, int k) {
if(a[o].l >= l && a[o].r <= r) {
sum += a[o].find_num(k);
return;
}
int mid = a[o].l + (a[o].r - a[o].l)/2;
if(mid >= l)
find_rank(o*2, l, r, k);
if(mid < r)
find_rank(o*2+1, l, r, k);
}//找到k这个数字在l到r中排名为多少；

void rank_k(int l, int r, int k) {
int ml = 0, mr = 6, mid, ans = 0;
while(ml < mr) {
mid = mr - (mr-ml)/2;
sum = 1;
find_rank(1, l, r, mid);
if(sum > k)
mr = mid-1;
else
ml = mid;
}
printf("%d\n", mr);
}

int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &c[i]);
build(1, 1, n);
for(int i = 1; i <= m; i++) {
getchar();
char s;
scanf("%c", &s);
int l, r, k, x;
if(s == 'Q') {
scanf("%d%d%d", &l, &r, &k);
rank_k(l, r, k);
}
if(s == 'C') {
scanf("%d%d", &x, &k);
update(1, x, k);
}
}
tot = 0;
memset(a, 0, sizeof(a));
}
return 0;
}

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客