BZOJ 1901 Zju2112 Dynamic Rankings 树状数组套线段树

时间:2023-03-08 16:24:33
BZOJ 1901 Zju2112 Dynamic Rankings 树状数组套线段树

题意概述:带修改求区间第k大。

分析:

  我们知道不带修改的时候直接上主席树就可以了对吧?两个版本号里面的节点一起走在线段树上二分,复杂度是O((N+M)logN)。

  然而这里可以修改,主席树显然是凉了,但是注意到主席树的不带修改做法实际上是利用的差分的性质,即主席树本身实际上就是维护的一个前缀和一样的东西。想想普通的前缀和问题,我们求带修改前缀和是怎么做的?树状数组!于是我们用树状数组套线段树,树状数组里面每个点是一棵权值线段树,维护的是位置i前面lowbit(i)范围中的元素的权值信息,每一次更新的时候在logN棵线段树里修改,询问的时候logN棵线段树里一起走,在线段树上二分(树状数组套在外面写起来简单)。

  由于这个题对时间效率要求不是很高我就直接动态开点了没有离散化也没有卡常。实际上就是我比较懒

  时间复杂度O((N+M)logN^2)

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int maxn=;
const int up=; int N,M,a[maxn];
struct mstruct{
static const int maxnode=;
static const int maxl=;
int rt[maxl],np,lc[maxnode],rc[maxnode],sz[maxnode];
int q1[maxl],q2[maxl],l1,l2;
mstruct(){ np=,sz[]=; memset(rt,,sizeof(rt)); }
int lowbit(int i){ return i&(-i); }
void pushup(int now){ sz[now]=sz[lc[now]]+sz[rc[now]]; }
void inupdate(int &now,int L,int R,int p,int v){
if(!now) now=++np,lc[now]=rc[now]=sz[now]=;
if(L==R){ sz[now]+=v; return; }
int m=L+R>>;
if(p<=m) inupdate(lc[now],L,m,p,v);
else inupdate(rc[now],m+,R,p,v);
pushup(now);
}
void update(int p,int v,bool c){
int i=p;
while(i<=N){
if(c) inupdate(rt[i],,up,a[p],-);
inupdate(rt[i],,up,v,);
i+=lowbit(i);
}
a[p]=v;
}
void mov(bool rig){
for(int i=;i<l1;i++) q1[i]=rig?rc[q1[i]]:lc[q1[i]];
for(int i=;i<l2;i++) q2[i]=rig?rc[q2[i]]:lc[q2[i]];
}
int inquery(int L,int R,int k){
if(L==R) return L;
int m=L+R>>,s1=,s2=;
for(int i=;i<l1;i++) s1+=sz[lc[q1[i]]];
for(int i=;i<l2;i++) s2+=sz[lc[q2[i]]];
if(k<=s2-s1){ mov(); return inquery(L,m,k); }
mov(); return inquery(m+,R,k-(s2-s1));
}
int query(int L,int R,int k){
l1=l2=;
int i=L; while(i) q1[l1++]=rt[i],i-=lowbit(i);
i=R; while(i) q2[l2++]=rt[i],i-=lowbit(i);
return inquery(,up,k);
}
}tt; void data_in()
{
scanf("%d%d",&N,&M);
for(int i=;i<=N;i++) scanf("%d",&a[i]);
for(int i=;i<=N;i++) tt.update(i,a[i],);
}
void work()
{
char op[];
int l,r,k,t;
for(int i=;i<=M;i++){
scanf("%s",op);
if(op[]=='C'){
scanf("%d%d",&l,&t);
tt.update(l,t,);
}
else if(op[]=='Q'){
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",tt.query(l-,r,k));
}
}
}
int main()
{
data_in();
work();
return ;
}