标签:nbsp lower 区间 查错 return can har col span
树状数组套主席树
/* 树状数组套主席树 静态建树 动态修改 树状数组的每个点都包含了整个值域 */ #include<cstdio> #include<cstring> #include<algorithm> #define mid ((l+r)>>1) using namespace std; const int N=1e5+50,M=400*N; // N*(logN)^2 树空间 不是40*N 是20*20=400.... int n,m,T,tot,a[N],b[N<<1],rt[N]; int op[N],ask1[N],ask2[N],ask3[N]; int S[M],L[M],R[M],askl[40],askr[40]; void add(int x,int c) // 将 a[x] 加入树状数组 { int k=lower_bound(b+1,b+m+1,a[x])-b;// 离散后的值 for(int i=x;i<=n;i+=(i&-i)) { int*t=&rt[i],l=1,r=m; // 利用指针 直接修改 while(l!=r) { if(!*t) *t=++tot; S[*t]+=c; // 动态开点 if(k<=mid) r=mid,t=&L[*t]; else l=mid+1,t=&R[*t]; } if(!*t) *t=++tot; S[*t]+=c; } } int ask(int l,int r,int k) { int sum,pl=0,pr=0; for(int i=l-1;i;i-=(i&-i)) askl[++pl]=rt[i]; for(int i=r;i;i-=(i&-i)) askr[++pr]=rt[i]; //记录目前区间的左右树 l=1,r=m; while(l!=r) { sum=0; for(int i=1;i<=pr;i++) sum+=S[L[askr[i]]]; for(int i=1;i<=pl;i++) sum-=S[L[askl[i]]]; // 错写成 askr 查错++ // 计算目前区间左边部分的数的数量 if(k<=sum) // 和静态的一样 判断左右 { for(int i=1;i<=pl;i++) askl[i]=L[askl[i]]; for(int i=1;i<=pr;i++) askr[i]=L[askr[i]]; r=mid; } else { for(int i=1;i<=pl;i++) askl[i]=R[askl[i]]; for(int i=1;i<=pr;i++) askr[i]=R[askr[i]]; l=mid+1,k-=sum; } } return b[l]; } int main() { scanf("%d%d",&n,&T); m=n; for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]; for(int i=1;i<=T;i++) { char ch[10];scanf("%s",ch); if(ch[0]==‘Q‘) op[i]=1; scanf("%d%d",&ask1[i],&ask2[i]); if(!op[i]) b[++m]=ask2[i]; // 先统计所有可能涉及到的数字 然后离散化 else scanf("%d",&ask3[i]); } sort(b+1,b+m+1); m=unique(b+1,b+m+1)-b-1; for(int i=1;i<=n;i++) add(i,1); for(int i=1;i<=T;i++) { if(op[i]) printf("%d\n",ask(ask1[i],ask2[i],ask3[i])); else add(ask1[i],-1),a[ask1[i]]=ask2[i],add(ask1[i],1); } return 0; }
标签:nbsp lower 区间 查错 return can har col span
原文地址:https://www.cnblogs.com/lxy8584099/p/10336963.html