P2617 Dynamic Rankings
P2617 Dynamic Rankings
题目描述
给定一个含有
Q l r k
表示查询下标在区间 中的第 小的数C x y
表示将 改为
【数据范围】
对于
Solution:
生套生 模板题,用树状数组维护主席树的前缀和。
首先我们都知道主席树的本质其实是前缀和,如果我们要修改一个点的点权,那么就会牵扯到至多
还记得当年在学前缀和时老师同时教了另一个东西: 树状数组。我们在建树时,可以不按照线性前缀和,而在树状数组上建树,这样我们在单点修改时只用修改
#include<bits/stdc++.h> const int N=1e5+5; const int inf=1e9; using namespace std; inline int lowbit(int x){return x&-x;} int n,m; int a[N]; struct Segment_Tree{ struct Tree{ int ls,rs,cnt; }t[N*400]; int cnt,rt[N]; void insert(int &x,int l,int r,int pos,int k) { t[x=(x ? x : ++cnt)].cnt+=k; if(l==r)return ; int mid=l+r>>1; if(pos<=mid)insert(t[x].ls,l,mid,pos,k); if(mid<pos) insert(t[x].rs,mid+1,r,pos,k); } void update(int x,int val,int k) { for(int u=x;u<=n;u+=lowbit(u))insert(rt[u],0,inf,val,k); } int A[N],B[N]; int query(int x,int y,int k) { A[0]=B[0]=0; for(int u=x-1;u;u-=lowbit(u))A[++A[0]]=rt[u]; for(int u=y;u;u-=lowbit(u))B[++B[0]]=rt[u]; int l=0,r=inf,ans=0,mid=0,tmp; while(l<r) { mid=l+r>>1; tmp=0; for(int i=1;i<=A[0];i++)tmp-=t[t[A[i]].rs].cnt; for(int i=1;i<=B[0];i++)tmp+=t[t[B[i]].rs].cnt; if(tmp>=k) { for(int i=1;i<=A[0];i++)A[i]=t[A[i]].rs; for(int i=1;i<=B[0];i++)B[i]=t[B[i]].rs; l=ans=mid+1; } else { for(int i=1;i<=A[0];i++)A[i]=t[A[i]].ls; for(int i=1;i<=B[0];i++)B[i]=t[B[i]].ls; r=mid;k-=tmp; } } return ans; } }T; char c[10]; void work() { cin>>n>>m; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); T.update(i,a[i],1); } for(int i=1,x,y,k;i<=m;i++) { scanf("%s",c); scanf("%d%d",&x,&y); if(c[0]=='C') { T.update(x,a[x],-1); a[x]=y; T.update(x,a[x],1); } else { scanf("%d",&k); k=y-x+1-k+1; int ans=T.query(x,y,k); printf("%d\n",ans); } } } int main() { //freopen("Dynamic Rankings.in","r",stdin);freopen("Dynamic Rankings.out","w",stdout); work(); return 0; }