题目大意:
给你一个数组 a a a, a a a有两个操作
- 询问 a a a中 [ l , r ] [l,r] [l,r]区间里面第 k k k小的数是哪个?
- 修改 a x a_x ax为 y y y
解题思路:
首先我们知道权值线段树是可以求第 k k k小的数的,如果只有第一个问题那么就是一个主席树问题,但是主席树对于第二个问题,要修改 n n n棵树时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)的很大不行
我们知道主席树是怎么建立的?
是
r
o
o
t
[
i
]
继
承
了
r
o
o
t
[
i
−
1
]
的
到
的
连
续
区
间
的
权
值
线
段
树
root[i]继承了root[i-1]的到的连续区间的权值线段树
root[i]继承了root[i−1]的到的连续区间的权值线段树
因为你修改一个点你要把影响传到后面的所有的
r
o
o
t
root
root,那么开销很大
那么这个是不是很想树状数组??
树状数组修改的时候只把影响传给了后面的 l o g log log个节点,每次查询都要去询问 l o g log log个节点
那么我们的思路就来了,就是树状数组每个节点都是一个动态开点的权值线段树,现在我们要更新
a
5
a_5
a5,那么我们只有更新
r
o
o
t
[
5
,
6
,
8
,
16
]
root[5,6,8,16]
root[5,6,8,16]这4个节点的权值线段树
其实我们发现树状数组的作用是分层,把序列分成了 l o g log log层,每次这个影响只会传到每一层的一个点去
到时候查询的时候要 l o g log log个节点一起跳这样才能完整的统计影响
AC code
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
struct qu {
char op[2];
int l, r, k;
}q[maxn];
struct node {
int lson, rson;
int val;
}sgt[maxn * 40];
int n, root[maxn], cnt, m;
int arr[maxn];
vector<int> lis;
inline int getid(int x) {
return lower_bound(lis.begin(),lis.end(),x) - lis.begin() + 1;
}
inline void pushup(int rt) {
sgt[rt].val = sgt[sgt[rt].lson].val + sgt[sgt[rt].rson].val;
return;
}
inline void insert(int &rt, int l, int r, int pos, int val = 1) {
if(!rt) rt = ++ cnt;
if(l == r) {
sgt[rt].val += val;
return;
}
if(pos <= mid) insert(sgt[rt].lson,l,mid,pos,val);
else insert(sgt[rt].rson,mid+1,r,pos,val);
pushup(rt);
}
int jump[2][30], idx[2];
inline void pre_quary(int l, int r) {
idx[0] = idx[1] = 0;
while(l) {
jump[0][++idx[0]] = root[l];
l -= lowbit(l);
}
while(r) {
jump[1][++idx[1]] = root[r];
r -= lowbit(r);
}
}
int quary(int l, int r, int kth) {
if(l == r) return l;
int lsiz = 0, rsiz = 0;//log个节点一起条
for(int i = 1; i <= idx[0]; ++ i) lsiz += sgt[sgt[jump[0][i]].lson].val;
for(int i = 1; i <= idx[1]; ++ i) rsiz += sgt[sgt[jump[1][i]].lson].val;
if(kth <= rsiz - lsiz) {
for(int i = 1; i <= idx[0]; ++ i) jump[0][i] = sgt[jump[0][i]].lson;
for(int i = 1; i <= idx[1]; ++ i) jump[1][i] = sgt[jump[1][i]].lson;
return quary(l,mid,kth);
} else {
for(int i = 1; i <= idx[0]; ++ i) jump[0][i] = sgt[jump[0][i]].rson;
for(int i = 1; i <= idx[1]; ++ i) jump[1][i] = sgt[jump[1][i]].rson;
return quary(mid+1,r,kth-(rsiz-lsiz));
}
}
int main() {
IOS;
cin >> n >> m;
for(int i = 1; i <= n; ++ i) {
cin >> arr[i];
lis.push_back(arr[i]);
}
for(int i = 1; i <= m; ++ i){
cin >> q[i].op;
if(*q[i].op == 'C') cin >> q[i].l >> q[i].r, lis.push_back(q[i].r);
else cin >> q[i].l >> q[i].r >> q[i].k;
}
sort(lis.begin(),lis.end());
lis.erase(unique(lis.begin(),lis.end()),lis.end());
int len = lis.size() + 1;
for(int i = 1; i <= n; ++ i) {
arr[i] = getid(arr[i]);//像树状数组一样跟新
int j = i;
while(j < len) {
insert(root[j],1,len,arr[i]);
j += lowbit(j);
}
}
for(int i = 1; i <= m; ++ i) {
char op = *q[i].op;
if(op == 'C') {
int ax = q[i].l, y = q[i].r;
int j = ax;
while(j < len) {
insert(root[j],1,len,arr[q[i].l],-1);
j += lowbit(j);
}
j = ax;
arr[q[i].l] = getid(q[i].r);
while(j < len) {
insert(root[j],1,len,arr[q[i].l],1);
j += lowbit(j);
}
} else {
pre_quary(q[i].l-1,q[i].r);
cout << lis[quary(1,len,q[i].k) - 1] << "\n";
}
}
}