http://www.lydsy.com/JudgeOnline/problem.php?id=1901
我的可持久化线段树消耗的内存太大了,在zoj超内存
如果对 上次的那题无修改的区间第k大的可持久化做法足够了解http://blog.csdn.net/haha593572013/article
那么稍微理解一下就能理解这道题了
在求区间第k大的时候,我们的本质其实是求出一棵包含且只包含所求区间信息的线段树,然后在整棵线段树中查询区间第k大的数,当然这棵线段树是通过做差得出来的,其实就是两个“前缀线段树”相减得出来的,即保存1~y区间信息的线段树 与 保存1~ x 区间信息的线段树节点信息相减,因为上题没有更新,所以每次直接从i-1时刻的线段树插入一个数得到i时刻的线段树,每次得到的新的线段树保存的信息都是1~ i 的信息,即都是前缀的信息
注意到了吗?前缀!!!那么如果有更新的操作的话,我们只需要维护好前缀的信息就可以了
具体做法是用树状数组来维护前缀(线段树)和,树状数组的每个节点又是一棵线段树,所以复杂度就要多乘一个log(n),即nlog^2(n)
求解x y区间第k大的数的时候还是一样,1到y的信息减去1到x-1的信息
具体的细节大家耐心研究下吧,蛮有意思的(树套树)
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 120000;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int ls[maxn*20],rs[maxn*20],sum[maxn*20];
int root[maxn],tot;
void build(int l,int r,int &rt)
{
rt=++tot;
sum[rt]=0;
if(l==r) return ;
int m=l+r>>1;
build(l,m,ls[rt]);
build(m+1,r,rs[rt]);
}
void update(int last,int p,int l,int r,int &rt,int v)
{
rt=++tot;
ls[rt]=ls[last]; rs[rt]=rs[last];sum[rt]=sum[last]+v;
if(l==r) return ;
int m=l+r>>1;
if(p <= m) update(ls[last],p,l,m,ls[rt],v);
else update(rs[last],p,m+1,r,rs[rt],v);
}
int cc,n,m;
int num[maxn];
char op[10010][3];
const int NN = 10010;
int san[NN*2],P[NN],Q[NN],K[NN];
int L[30],R[30];
int N,M;
int query(int l,int r,int k)
{
if(l==r) return l;
int m=l+r>>1;
int suma=0,sumb=0;
for(int i=1;i<=N;i++) suma+=sum[ls[L[i]]];
for(int i=1;i<=M;i++) sumb+=sum[ls[R[i]]];
int del=sumb-suma;
if(k <= del) {
for(int i=1;i<=N;i++) L[i]=ls[L[i]];
for(int i=1;i<=M;i++) R[i]=ls[R[i]];
return query(l,m,k);
} else {
for(int i=1;i<=N;i++) L[i]=rs[L[i]];
for(int i=1;i<=M;i++) R[i]=rs[R[i]];
return query(m+1,r,k-del);
}
}
int ask(int l,int r,int k)
{
N=0,M=0;
for(;l>0;l-=l&-l) L[++N]=root[l];
for(;r>0;r-=r&-r) R[++M]=root[r];
return query(1,cc,k);
}
void Bit_update(int x,int val,int flag)
{
for(;x<=n;x+=x&-x)
{
update(root[x],val,1,cc,root[x],flag);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
san[++cc]=num[i];
}
for(int i=1;i<=m;i++)
{
scanf("%s%d%d",op[i],&P[i],&Q[i]);
if(op[i][0]=='Q'){ scanf("%d",&K[i]); }
else san[++cc]=Q[i];
}
sort(san+1,san+1+cc);
cc=unique(san+1,san+1+cc)-san-1;
for(int i=1;i<=n;i++) num[i]=lower_bound(san+1,san+1+cc,num[i])-san;
build(1,cc,root[0]);
for(int i=1;i<=n;i++) Bit_update(i,num[i],1);
for(int i=1;i<=m;i++) {
if(op[i][0]=='Q'){
int id=ask(P[i]-1,Q[i],K[i]);
printf("%d\n",san[id]);
} else {
int pos=lower_bound(san+1,san+1+cc,Q[i]) - san;
Bit_update(P[i],num[P[i]],-1);
num[P[i]] = pos;
Bit_update(P[i],num[P[i]],1);
}
}
return 0;
}