BZOJ1901(主席树+树状数组 实现“动态主席树”)
BZOJ1901: Zju2112 Dynamic Rankings##
Time Limit: 10 Sec
Memory Limit: 128 MBDescription###
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。
Input###
第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。
第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。
接下来的m行描述每条指令
每行的格式是下面两种格式中的一种。
Q i j k 或者 C i t
Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)
表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。
C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t
m,n≤10000
Output###
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Sample Input###
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output###
3
6
HINT
题目地址:BZOJ1901: Zju2112 Dynamic Rankings
题目大意: 题目很简洁了:)
题解:
对于不修改的情况
我们对每一个数都开一颗主席树(这里第i颗主席树记录前i个数的情况)
只要对目标区间的左右端点的主席树差分下就能求出 \(kth\)
如何支持动态
想到树状数组可以 \(logN\) 支持前缀和
我们只要像树状数组一样开主席树就可以了
例如第 \(c[8]\) 颗主席树记录的是 \(c[4]\)颗和\(c[6]\)颗和\(c[7]\)颗和第 \(8\) 个数的情况
对于每次修改只要修改 \(logN\)颗主席树,修改每个主席树上 \(logN\)个点
然后 orz hzw
AC代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1e4+5,M=2200001;
int n,m,tot,Lnum,Rnum;
int val[N],K[N],hash[N<<1],A[N],B[N];
char op[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int sz,sum[M],son[M][2],root[N];
void change(int u,int &v,int l,int r,int k,int x){
v=++sz;
sum[v]=sum[u]+x;
son[v][0]=son[u][0];
son[v][1]=son[u][1];
if(l==r)return;
int mid=(l+r)>>1;
if(k<=mid)change(son[u][0],son[v][0],l,mid,k,x);
else change(son[u][1],son[v][1],mid+1,r,k,x);
}
int L[30],R[30];
int query(int l,int r,int k){
if(l==r)return l;
int suml=0,sumr=0;
for(int i=1;i<=Lnum;i++)suml+=sum[son[L[i]][0]];
for(int i=1;i<=Rnum;i++)sumr+=sum[son[R[i]][0]];
int mid=(l+r)>>1;
if(sumr-suml>=k){
for(int i=1;i<=Lnum;i++)L[i]=son[L[i]][0];
for(int i=1;i<=Rnum;i++)R[i]=son[R[i]][0];
return query(l,mid,k);
}else{
for(int i=1;i<=Lnum;i++)L[i]=son[L[i]][1];
for(int i=1;i<=Rnum;i++)R[i]=son[R[i]][1];
return query(mid+1,r,k-(sumr-suml));
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
val[i]=hash[++tot]=read();
for(int i=1;i<=m;i++){
scanf("\n");
op[i]=getchar();
A[i]=read(),B[i]=read();
if(op[i]=='Q')K[i]=read();
else hash[++tot]=B[i];
}
sort(hash+1,hash+tot+1);
int New=unique(hash+1,hash+tot+1)-hash-1;
for(int i=1;i<=n;i++){
int k=lower_bound(hash+1,hash+New+1,val[i])-hash;
for(int j=i;j<=n;j+=j&(-j))
change(root[j],root[j],1,New,k,1);
}
for(int i=1;i<=m;i++)
if(op[i]=='Q'){
Lnum=0,Rnum=0;A[i]--;
for(int j=A[i];j>0;j-=j&(-j))
L[++Lnum]=root[j];
for(int j=B[i];j>0;j-=j&(-j))
R[++Rnum]=root[j];
printf("%d\n",hash[query(1,New,K[i])]);
}else{
int k;
k=lower_bound(hash+1,hash+New+1,val[A[i]])-hash;
for(int j=A[i];j<=n;j+=j&(-j))
change(root[j],root[j],1,New,k,-1);
val[A[i]]=B[i];
k=lower_bound(hash+1,hash+New+1,B[i])-hash;
for(int j=A[i];j<=n;j+=j&(-j))
change(root[j],root[j],1,New,k,1);
}
return 0;
}
作者:skl_win
出处:https://www.cnblogs.com/shaokele/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。