【BZOJ】1901: Zju2112 Dynamic Rankings
【题意】带修改的查询区间第k小
【算法】树状数组套可持久化线段树
【题解】对于树状数组上的每个节点,维护可持久化权值线段树(节点为权值),从而达到查询前缀和的目的。
对于每次修改,在待修改线段树基础上运用可持久化性质来修改,先删除原数字,再加入新数字。
注意记录修改后的原数字,方便后来删除。
★注意区分权值范围和数组范围的区别!!!
复杂度O(n log2n)。
注意点全部标注在代码中,细节巨多。
#include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespace std; int read() { char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c=='-')t=-1; do{s=s*10+c-'0';}while(isdigit(c=getchar())); return s*t; } const int maxn=10010; struct tree{int l,r,sum;}t[10000010];//空间开大!!!100w都过不去啊。。。 char s[10]; int cnt1,cnt2,a1[maxn],a2[maxn],a[maxn],b1[maxn],b2[maxn],b3[maxn],n,m,root[maxn],tot,c[maxn*2],sz=0; void insert(int l,int r,int x,int &y,int v,int c){ y=++sz;//设置新节点!!! t[y]=t[x];t[y].sum+=c; if(l==r)return; int mid=(l+r)>>1; if(v<=mid)insert(l,mid,t[x].l,t[y].l,v,c); else insert(mid+1,r,t[x].r,t[y].r,v,c); } int ask(int l,int r,int v){ if(l==r)return l; int sum=0; for(int i=1;i<=cnt1;i++)sum-=t[t[a1[i]].l].sum; for(int i=1;i<=cnt2;i++)sum+=t[t[a2[i]].l].sum; int mid=(l+r)>>1; if(sum>=v){ for(int i=1;i<=cnt1;i++)a1[i]=t[a1[i]].l; for(int i=1;i<=cnt2;i++)a2[i]=t[a2[i]].l; return ask(l,mid,v); } else{ for(int i=1;i<=cnt1;i++)a1[i]=t[a1[i]].r; for(int i=1;i<=cnt2;i++)a2[i]=t[a2[i]].r; return ask(mid+1,r,v-sum);//转入右边要减去左边的 } } int lowbit(int x){return x&(-x);} void modify(int x,int k,int p){for(int i=x;i<=n;i+=lowbit(i))insert(1,tot,root[i],root[i],k,p);} //分清,tot是权值线段树范围,n是数组范围 int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ a[i]=read(); c[++tot]=a[i]; } for(int i=1;i<=m;i++){ scanf("%s%d%d",s,&b1[i],&b2[i]); if(s[0]=='Q')b3[i]=read(); else c[++tot]=b2[i]; } sort(c+1,c+tot+1); tot=unique(c+1,c+tot+1)-c-1; for(int i=1;i<=n;i++)a[i]=lower_bound(c+1,c+tot+1,a[i])-c; for(int i=1;i<=m;i++)if(!b3[i])b2[i]=lower_bound(c+1,c+tot+1,b2[i])-c; for(int i=1;i<=n;i++)modify(i,a[i],1); for(int i=1;i<=m;i++){ if(b3[i]){ cnt1=0;cnt2=0; for(int j=b1[i]-1;j>=1;j-=lowbit(j))a1[++cnt1]=root[j]; for(int j=b2[i];j>=1;j-=lowbit(j))a2[++cnt2]=root[j];//用根啊老铁 printf("%d\n",c[ask(1,tot,b3[i])]);//询问给的是离散化后的值,要还原 } else{ modify(b1[i],a[b1[i]],-1); a[b1[i]]=b2[i]; modify(b1[i],b2[i],1); } } return 0; }