题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112
题目大意:
比静态查询区间第k小多加了一个修改操作。
题目分析:
对于所有的数(原序列的数和要修改的数)都离散化处理,
动态修改的核心是对于树状数组中出现的点开线段树维护,
因为之前修改一个数对于后续区间有影响,我们令开一个根节点数组S
来维护供树状数组修改的线段树,把每个数修改过后的影响丢到S里面去,
然后每次查询的时候,把树状数组中可能用到的值记录下来,再通过这些记录
用树状数组的方法查询。
整体还是在离线,空间复杂度:O((n+m)log(n)*log(m))
#include<bits/stdc++.h>
using namespace std;#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define ll long long#define lrt int l,int r,int rt
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define root l,r,rt
#define mst(a,b) memset((a),(b),sizeof(a))
#define pii pair<int,int>
#define fi first
#define se second
#define mk(x,y) make_pair(x,y)
const int mod=1e9+7;
const int maxn=6e4+5;
const int Maxn=maxn<<5;
const int ub=1e6;
const double inf=1e-4;
ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
/*
题目大意:
比静态查询区间第k小多加了一个修改操作。题目分析:
对于所有的数(原序列的数和要修改的数)都离散化处理,
动态修改的核心是对于树状数组中出现的点开线段树维护,
因为之前修改一个数对于后续区间有影响,我们令开一个根节点数组S
来维护供树状数组修改的线段树,把每个数修改过后的影响丢到S里面去,
然后每次查询的时候,把树状数组中可能用到的值记录下来,再通过这些记录
用树状数组的方法查询。
整体还是在离线,空间复杂度:O((n+m)log(n)*log(m))
*/int n,m,a[maxn],b[maxn],cnt,x,y;
char tp[10];
struct Q{int x,y,z;bool flag;
}q[maxn];int tot=0,rt[Maxn],L[Maxn],R[Maxn],sum[Maxn];
void build(int& o,int l,int r){o=++tot,sum[o]=0;if(l==r) return ;int mid=l+r>>1;build(L[o],l,mid);build(R[o],mid+1,r);
}
void update(int& o,int l,int r,int pre,int v,int pv){o=++tot;L[o]=L[pre],R[o]=R[pre];sum[o]=sum[pre]+pv;///cout<<l<<" "<<r<<endl;if(l==r) return ;int mid=l+r>>1;if(v<=mid) update(L[o],l,mid,L[pre],v,pv);else update(R[o],mid+1,r,R[pre],v,pv);
}
int used[maxn],S[maxn];///对于树状数组的每个点都建树
int lowbit(int x){return x&-x;}
void add(int x,int v,int pv){for(;x<=n;update(S[x],1,n,S[x],v,pv),x+=lowbit(x));
}
int Sum(int x){int ret=0;for(;x>0;ret+=sum[L[used[x]]],x-=lowbit(x));return ret;
}
int query(int u,int v,int lu,int lv,int l,int r,int V){if(l>=r) return l;int ret=Sum(v)-Sum(u)+sum[L[lv]]-sum[L[lu]];int mid=l+r>>1;if(V<=ret){for(int i=v;i;i-=lowbit(i)) used[i]=L[used[i]];for(int i=u;i;i-=lowbit(i)) used[i]=L[used[i]];return query(u,v,L[lu],L[lv],l,mid,V);}else{for(int i=v;i;i-=lowbit(i)) used[i]=R[used[i]];for(int i=u;i;i-=lowbit(i)) used[i]=R[used[i]];return query(u,v,R[lu],R[lv],mid+1,r,V-ret);}
}int main(){int t;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);cnt=0,mst(sum,0);rep(i,1,n+1) {scanf("%d",&a[i]);b[++cnt]=a[i];}rep(i,1,m+1){scanf("%s",tp);if(tp[0]=='Q'){scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].z);q[i].flag=true;}else{scanf("%d%d",&q[i].x,&q[i].y);b[++cnt]=q[i].y;q[i].flag=false;}}sort(b+1,b+cnt+1);cnt=unique(b+1,b+1+cnt)-(b+1);tot=0;build(rt[0],1,cnt);///建立一颗空树rep(i,1,n+1){int val=lower_bound(b+1,b+1+cnt,a[i])-b;update(rt[i],1,cnt,rt[i-1],val,1);S[i]=rt[0];}///插值n=cnt;///rep(i,1,m+1){if(q[i].flag){for(int j=q[i].x-1;j;j-=lowbit(j)) used[j]=S[j];for(int j=q[i].y;j;j-=lowbit(j)) used[j]=S[j];///更新树状数组的值///cout<<rt[q[i].y]<<" "<<L[rt[q[i].y]]<<" "<<sum[L[rt[q[i].y]]]<<endl;printf("%d\n",b[query(q[i].x-1,q[i].y,rt[q[i].x-1],rt[q[i].y],1,n,q[i].z)]);}else{int val1=lower_bound(b+1,b+1+n,a[q[i].x])-b;int val2=lower_bound(b+1,b+1+n,q[i].y)-b;add(q[i].x,val1,-1),add(q[i].x,val2,1);a[q[i].x]=q[i].y;}}}return 0;
}