题目描述 Description
人类喜欢许下各种各样的祈愿,祈愿的感应强度是可以用数值来表示的,感应强度较强的祈愿会首先被神灵所响应而得到实现.
但是因为人类的祈愿太多了,现在SatiyaAugust已经没有办法很快的选出她想要帮助人类实现的祈愿了.
现在有一些祈愿,每个祈愿有自己的数值,SatiyaAugust让这些祈愿排成了一列.她会向你询问在一段区间l~r中第k大的祈愿,但是人类是一种奇怪的生物,他们的祈愿大小会发生变化.
一句话题意:单点修改动态k区间第k小
输入描述 Input Description
第一行一个数T,表示数据组数.
每组数据第一行是两个数n,m,n表示祈愿数目,m表示修改和询问的总数.
接下来一行n个数,表示n个祈愿初始数值.
接下来m行
每行开头是一个字母
若为Q,则下面有三个整数l,r,k,表示查询a[l]~a[r]中第k小
若为C,则接下来两个整数x,k,表示修改a[x]为k
输出描述 Output Description
对每个询问,输出相应的值
样例输入 Sample Input
1
2 3
1 2
Q 1 2 1
C 1 3
Q 1 2 1
样例输出 Sample Output
1
2
数据范围及提示 Data Size & Hint
T<=5
N<=50000 M<=10000 0<=a[i]<=10^9
做CA爷的题目前当然应该先%%%CA爷辣!
首先看到多组询问不要害怕。。。因为时限有4s,可以当做1组询问1s来做(反正最多5组 哼~) 但是不要想水分。。。亲测全都是5w的。。。良心数据。。(别打喔)
那我们来分析一下这道题。。。
做法有很多。。首先讨论喔不会的那种。。。分块。
时间复杂度O(m*sqrt(n)*logn*logn)空间复杂度O(n)然后。。。没有然后了都说了我不会←_←
第二种:权值线段树套区间树 这个做法首先要注意的是一定要离散化权值,毕竟10^9。。还有就是不要省空间,256MB足够你干很多事了,拿空间换时间很实惠的。。。
第三种:归并树。顾名思义,利用归并排序的思想在线段树上实现。然而并不是排序!!!每一个节点记录两个序列:一个有序,一个无序。然后从底向上逐渐合并实现查询区间第K大。单点修改复杂度O(nlogn),总复杂度O(nlognlogn)美中不足的是写起来麻烦。。。(但是比第二种简单)
第四种:手写set。。这个应该需要@P党(绝不是语言歧视。。而是C艹党除了大神没有手写set的习惯。。)
(我也只是想出来了做法所以就贴个原题题解的程序了。。。。不要吐槽我)
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN(50010);
template<typename T>
bool checkmin(T &a, const T &b){
return b < a? (a = b, true): false;
}
template<typename T>
bool checkmax(T &a, const T &b){
return b > a? (a = b, true): false;
}
struct RAND{
int rn[MAXN], si, n;
void init(int n){
this->n = n;
srand(2357);
for(int i = 0; i < n; ++i) rn[i] = rand();
si = 0;
}
int query(){
if(si >= n) si -= n;
return rn[si++];
}
} ra;
struct NODE1{
int ke, b, si;
NODE1 *ch[2];
} *NIL1;
struct POOL1{
NODE1 pool[MAXN*19], *last;
void init(){
last = pool;
}
NODE1 *all(int k){
last->ch[0] = last->ch[1] = NIL1;
last->ke = k;
last->b = ra.query();
last->si = 1;
return last++;
}
} pool1;
inline void rep(NODE1 *rt){
if(rt == NIL1) return;
rt->si = rt->ch[0]->si+rt->ch[1]->si+1;
}
void rot(NODE1 *&rt, int f){
NODE1 *s = rt->ch[f];
rt->ch[f] = s->ch[!f];
s->ch[!f] = rt;
rep(rt);
rep(s);
rt = s;
}
void Insert(NODE1 *&rt, int k){
if(rt == NIL1){
rt = pool1.all(k);
return;
}
int t = (k >= rt->ke);
Insert(rt->ch[t], k);
if(rt->ch[t]->b > rt->b) rot(rt, t);
rep(rt);
}
void Erase(NODE1 *&rt, int k){
if(rt->ke == k){
if(rt->ch[0] == NIL1 || rt->ch[1] == NIL1){
rt = rt->ch[rt->ch[0] == NIL1];
return;
}
int t = rt->ch[0]->b < rt->ch[1]->b;
rot(rt, t);
Erase(rt->ch[!t], k);
rep(rt);
return;
}
Erase(rt->ch[k >= rt->ke], k);
rep(rt);
}
int Lower_bound(NODE1 *rt, int k){
if(rt == NIL1) return 0;
if(k <= rt->ke) return Lower_bound(rt->ch[0], k);
return rt->ch[0]->si+1+Lower_bound(rt->ch[1], k);
}
int arr[MAXN];
NODE1 *srt[MAXN << 2];
int query(int ql, int qr, int k, int l, int r, int rt){
if(srt[rt] == 0){
srt[rt] = NIL1;
for(int i = l; i <= r; ++i) Insert(srt[rt], arr[i]);
}
if(ql <= l && qr >= r) return Lower_bound(srt[rt], k);
int m = (l+r)/2, ret = 0;
if(ql <= m) ret += query(ql, qr, k, l, m, rt << 1);
if(qr > m) ret += query(ql, qr, k, m+1, r, (rt << 1)|1);
return ret;
}
void update(int loc, int k, int l, int r, int rt){
if(srt[rt] == 0){
srt[rt] = NIL1;
for(int i = l; i <= r; ++i) Insert(srt[rt], arr[i]);
}
if(l <= loc && loc <= r){
Erase(srt[rt], arr[loc]);
Insert(srt[rt], k);
}
if(l == r) return;
int m = (l+r)/2;
if(loc <= m) update(loc, k, l, m, rt << 1);
else update(loc, k, m+1, r, (rt <<1)|1);
}
int main(){
ra.init(50000);
NIL1 = new NODE1();
NIL1->ch[0] = NIL1->ch[1] = NIL1;
NIL1->b = -1;
NIL1->si = 0;
int TC;
scanf("%d", &TC);
while(TC--){
int n, M, a, b, c;
char s[2];
scanf("%d%d", &n, &M);
pool1.init();
memset(srt, 0, sizeof(srt));
int mi = 1000000001, mx = -1;
for(int i = 1; i <= n; ++i){
scanf("%d", arr+i);
checkmin(mi, arr[i]);
checkmax(mx, arr[i]);
}
for(int i = 0; i < M; ++i){
scanf("%s", s);
if(s[0] == 'Q'){
scanf("%d%d%d", &a, &b, &c);
int l = mi, r = mx, m, t;
while(l <= r){
m = (l+r)/2;
t = query(a, b, m, 1, n, 1);
if(t < c) l = m+1;
else r = m-1;
}
printf("%d\n", l-1);
}else{
scanf("%d%d", &a, &b);
update(a, b, 1, n, 1);
arr[a] = b;
checkmin(mi, b);
checkmax(mx, b);
}
}
}
return 0;
}