题目:
题意:
多组数据,对于每组数据,先读入两个值N,M,表示一个N个数的数列,有M次操作。
接下来一行读入数列的值。对于操作分为两种C i j 表示把数列中第I个数的值改为j, Q i j k 表示求区间[I,J]的第k小。
题解:
什么你还修改了?正解就是树状数组套主席树(传说中的树套树?)
这是一道模板啦
很好的讲解
主要的步骤如下
首先我们还是建好我们静态的主席树,注意要把那些改变后加进来的值一同加进来(先空好位置)
对于更新, 我们不改变这些已经建好的树,而是另建一批树S,用来记录更新,而这批线段树,我们用树状数组来维护,树状数组的每个节点都是一颗线段树
当查询的时候, 对树T的操作与静态的一致,另外再加上S树的值就好了
再用下标我是要疯掉的,我们不如每次二分吧。。
下面是关于空间的讨论,设总共不一样的数为s
如果我们建立一棵主席树在上面进行修改的话,我们的空间复杂度是
O(s∗logs∗logn)
分分钟被卡
但如果另建一批树S,空间就是
O(nlogs+m∗logn∗logs)
如果你去ZOJ2112的话,多组数据告诉你清零要清root,更小的空间限制告诉你要用更加优秀的空间(第二种方法)
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=50005;
struct hh{int l,r,w;}t[N*50];
int root[N*2],p[30],q[30],s,sz,n,pp,qq,a[N],b[N*2],L[N],R[N],pos[N],K[N];
char O[N];
void insert(int &now,int l,int r,int v,int x){
t[++sz]=t[now]; now=sz;
t[now].w+=v;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) insert(t[now].l,l,mid,v,x);
else insert(t[now].r,mid+1,r,v,x);
}
void bit_insert(int i,int v,int x)
{
for (;i<=n;i+=i&(-i)) insert(root[i],1,s,v,x);
}
int qurry(int l,int r,int k)
{
if (l==r) return l;
int mid=(l+r)>>1,suml=0,sumr=0;
for (int i=1;i<=pp;i++) suml+=t[t[p[i]].l].w;
for (int i=1;i<=qq;i++) sumr+=t[t[q[i]].l].w;
if (sumr-suml>=k)
{
for (int i=1;i<=pp;i++) p[i]=t[p[i]].l;
for (int i=1;i<=qq;i++) q[i]=t[q[i]].l;
return qurry(l,mid,k);
}
else
{
for (int i=1;i<=pp;i++) p[i]=t[p[i]].r;
for (int i=1;i<=qq;i++) q[i]=t[q[i]].r;
return qurry(mid+1,r,k-(sumr-suml));
}
}
int work(int l,int r,int k)
{
pp=0;qq=0;
if (l>0) p[++pp]=root[l+n];//若l=0则不能将root[n]加到p中
q[++qq]=root[r+n];
//加上原主席树的值
for (;l>=1;l-=l&(-l)) p[++pp]=root[l];
for (;r>=1;r-=r&(-r)) q[++qq]=root[r];
return qurry(1,s,k);
}
int main()
{
int T,m;scanf("%d",&T);
while (T--)
{
s=sz=0;
memset(root,0,sizeof(root));
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[++s]=a[i];
for (int i=1;i<=m;i++)
{
char st[2];scanf("%s%d%d",st,&L[i],&R[i]); O[i]=st[0];
if (st[0]=='Q') scanf("%d",&K[i]);
else b[++s]=R[i];
}
sort(b+1,b+s+1);
s=unique(b+1,b+s+1)-b-1;//利用去重函数得到节点数
for (int i=1;i<=n;i++) pos[i]=lower_bound(b+1,b+s+1,a[i])-b;//pos记录每个值在主席树中的位置,第i个位置的数排第几
for (int i=1;i<=n;i++)
{
root[i+n]=root[i+n-1];
insert(root[i+n],1,s,1,pos[i]);
}
for (int i=1;i<=m;i++)
if (O[i]=='Q')
{
int ans=work(L[i]-1,R[i],K[i]);
printf("%d\n",b[ans]);
}
else
{
bit_insert(L[i],-1,pos[L[i]]);//消除原先值的影响
pos[L[i]]=lower_bound(b+1,b+s+1,R[i])-b;//更新pos值
bit_insert(L[i],1,pos[L[i]]);//加入更新值的影响
}
}
}