树状数组套权值线段树
首先要知道权值线段可以处理全局第 K 大;主席树可以处理静态区间第 K 大,所谓静态就是不能改变值;但是如果有修改操作,用主席树做,每次要修改,后面的所有主席树都要进行一次修改,复杂度为 O(n); 显然是不行的;
这里就可以用到树状数组维护前缀和,权值线段树维护区间信息;
换句话说就是树状数组每个结点换成权值线段树,主体思想还是跟主席树一样,利用前缀和求某个区间第 K 大(或者其他操作);
全部代码都是这道题:
个人认为最难理解的就是建树部分,这建树还是跟主席树一样的思想,只是第 i 颗树不再是第 i-1 颗树转化过来,而是第 i 颗树转化过来,也就是说当你又更新第 i 颗树时,第 i 棵树要从原来的第 i 颗树转化过来;
例如:又更新第 i 棵树的某个值,只要在原来的第 i 棵树上再加一条链就行;跟主席树的思路还是一样的;
int update(int pre,int l,int r,int pos,int s){
int rt=++tot;
L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+s;
int d=(l+r)>>1;
if(l<r){
if(pos<=d) L[rt]=update(L[pre],l,d,pos,s);
else R[rt]=update(R[pre],d+1,r,pos,s);
}
return rt;
}
void add(int p,int q){//树状数组操作
int pos=lower_bound(b+1,b+cnt+1,a[p])-b;
while(p<=cnt){
tr[p]=update(tr[p],1,cnt,pos,q);
p+=lowbit(p);
}
}
查询操作,跟主席树的思路还是一样的,只不过不再是 sum[L[nw]]-sum[L[pre]];(这里的nw代表第 r 棵树的根结点,pre代表第 l 棵树的根结点);
而是根据树状数组求出要算的 l ,和要算的 r,然后循环加上减去就行;
代码:
int query(int l,int r,int k){
if(l==r) return l;
int s=0;
int d=(l+r)>>1;
for(int i=0;i<vr.size();i++) s+=sum[L[vr[i]]];
for(int i=0;i<vl.size();i++) s-=sum[L[vl[i]]];
if(s>=k){
for(int i=0;i<vr.size();i++) vr[i]=L[vr[i]];
for(int i=0;i<vl.size();i++) vl[i]=L[vl[i]];
return query(l,d,k);
}
else{
for(int i=0;i<vr.size();i++) vr[i]=R[vr[i]];
for(int i=0;i<vl.size();i++) vl[i]=R[vl[i]];
return query(d+1,r,k-s);
}
}
总代码:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=100100;
const int M=10000000;
const LL mod=100000000;
int n,m,cnt,tot,a[N*2],b[N*2],c[N*2],tr[N*2],L[N*400],R[N*400],sum[N*400];
struct Node{
char s[10];
int l,r,k;
}que[N];//问题
vector<int>vl,vr;
int lowbit(int k){ return k & (-k); }
int update(int pre,int l,int r,int pos,int s){
int rt=++tot;
L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+s;
int d=(l+r)>>1;
if(l<r){
if(pos<=d) L[rt]=update(L[pre],l,d,pos,s);
else R[rt]=update(R[pre],d+1,r,pos,s);
}
return rt;
}
void add(int p,int q){
int pos=lower_bound(b+1,b+cnt+1,a[p])-b;
while(p<=cnt){
tr[p]=update(tr[p],1,cnt,pos,q);
p+=lowbit(p);
}
}
int query(int l,int r,int k){
if(l==r) return l;
int s=0;
int d=(l+r)>>1;
for(int i=0;i<vr.size();i++) s+=sum[L[vr[i]]];
for(int i=0;i<vl.size();i++) s-=sum[L[vl[i]]];
if(s>=k){
for(int i=0;i<vr.size();i++) vr[i]=L[vr[i]];
for(int i=0;i<vl.size();i++) vl[i]=L[vl[i]];
return query(l,d,k);
}
else{
for(int i=0;i<vr.size();i++) vr[i]=R[vr[i]];
for(int i=0;i<vl.size();i++) vl[i]=R[vl[i]];
return query(d+1,r,k-s);
}
}
int main(){
// ios::sync_with_stdio(false);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
int ge=n;
for(int i=1;i<=m;i++){
scanf("%s",que[i].s);
if(que[i].s[0]=='Q') scanf("%d%d%d",&que[i].l,&que[i].r,&que[i].k);
else scanf("%d%d",&que[i].l,&que[i].r);b[++ge]=que[i].r;
}
sort(b+1,b+ge+1);
cnt=unique(b+1,b+ge+1)-b-1;
for(int i=1;i<=n;i++) add(i,1);
for(int i=1;i<=m;i++){
if(que[i].s[0]=='Q'){
vl.clear(),vr.clear();
que[i].l-=1;
while(que[i].l){//预处理要求的树
vl.push_back(tr[que[i].l]);
que[i].l-=lowbit(que[i].l);
}
while(que[i].r){//预处理要求的树
vr.push_back(tr[que[i].r]);
que[i].r-=lowbit(que[i].r);
}
printf("%d\n",b[query(1,cnt,que[i].k)]);
}
else{
add(que[i].l,-1);
a[que[i].l]=que[i].r;
add(que[i].l,1);
}
}
return 0;
}