思路:数据结构
提交:Inf次
题解:
树状数组套主席树
考虑静态区间第k大是一个前缀主席树,但是如果修改是 (O(nlogn)) 的,查询时 (O(logn)) ,考虑去均衡两部分的复杂度,如何均衡的维护前缀和?于是上了树状数组。于是乎主席树 (i) 维护的是 ([i-lowbit(i)+1,i]) 的区间信息。这样修改时 (O(log^2n)) ,查询也是 (O(log^2n))。
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define R register int
const int N=100010,Inf=0x3f3f3f3f;
using namespace std;
inline int g() {
R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,m,mxn,tot,cnt;
int a[N],add[N<<8],ll[N<<8],rr[N<<8],sum[N<<8],c[N],LL[30],RR[30],rt[N];
struct que{int k,x,y,z;que() {}
que(int kk,int xx,int yy,int zz) {k=kk,x=xx,y=yy,z=zz;}
} q[N];
inline int lbt(int x) {return x&-x;}
inline void change(int& tr,int l,int r,int pos,int v) {
if(!tr) tr=++tot; sum[tr]+=v; if(l==r) return ; R md=l+r>>1;
pos<=md?change(ll[tr],l,md,pos,v):change(rr[tr],md+1,r,pos,v);
}
inline void calc(int pos,int v,int d) {for(;pos<=n;pos+=lbt(pos)) change(rt[pos],1,mxn,v,d);}
inline int query(int l,int r,int k) {
if(l==r) return l; R md=l+r>>1,ans=0;
for(R i=1;i<=LL[0];++i) ans-=sum[ll[LL[i]]];
for(R i=1;i<=RR[0];++i) ans+=sum[ll[RR[i]]];
if(ans>=k) {
for(R i=1;i<=LL[0];++i) LL[i]=ll[LL[i]];
for(R i=1;i<=RR[0];++i) RR[i]=ll[RR[i]];
return query(l,md,k);
} else {
for(R i=1;i<=LL[0];++i) LL[i]=rr[LL[i]];
for(R i=1;i<=RR[0];++i) RR[i]=rr[RR[i]];
return query(md+1,r,k-ans);
}
}
inline int ask(int l,int r,int k) {
--l; LL[0]=RR[0]=0; memset(LL,0,sizeof(LL)),memset(RR,0,sizeof(RR));
for(;l;l-=lbt(l)) LL[++LL[0]]=rt[l];
for(;r;r-=lbt(r)) RR[++RR[0]]=rt[r];
return query(1,mxn,k);
}
signed main() {
n=g(),m=g(); for(R i=1;i<=n;++i) a[i]=g(),add[++cnt]=a[i];
for(R i=1;i<=m;++i) { register char ch;
while(!isalpha(ch=getchar())); R x=g(),y=g(),z;
if(ch=='Q') z=g(),q[i]=que(1,x,y,z);
else q[i]=que(0,x,y,0),add[++cnt]=y;
} sort(add+1,add+cnt+1); mxn=unique(add+1,add+cnt+1)-add-1;
for(R i=1;i<=n;++i)
a[i]=lower_bound(add+1,add+mxn+1,a[i])-add,calc(i,a[i],1);
for(R i=1;i<=m;++i) {
R x=q[i].x,y=q[i].y,z;
if(q[i].k) z=q[i].z,printf("%d
",add[ask(x,y,z)]);
else calc(x,a[x],-1),a[x]=lower_bound(add+1,add+mxn+1,y)-add,calc(x,a[x],1);
} //system("pause");
}
权值线段树套区间线段树
然而他T了(BZOJ上不会T)
外层权值自带二分属性,可以(O(log^2n))查询,(O(log^2n))修改。
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
static char B[1<<22],*S=B,*T=B;
#define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++)
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=100010;
int n,m,a[N],b[N<<1],cnt;
namespace Int{
const int M=N*17*16; int tot,top,stk[N*17];
struct node {int ls,rs,sum;} t[M];
#define ls t[tr].ls
#define rs t[tr].rs
#define sum(tr) t[tr].sum
inline void change(int& tr,int l,int r,int p,int d) {
if(!tr) {if(top) tr=stk[top--]; else tr=++tot;}
if(l==r) {sum(tr)+=d; if(!sum(tr)) stk[++top]=tr,tr=0; return ;}
R md=l+r>>1; if(p<=md) change(ls,l,md,p,d); else change(rs,md+1,r,p,d);
sum(tr)=sum(ls)+sum(rs);
}
inline int query(int tr,int l,int r,int LL,int RR) {
if(LL<=l&&r<=RR) return sum(tr); R md=l+r>>1,ret=0;
if(ls&&LL<=md) ret+=query(ls,l,md,LL,RR);
if(rs&&RR>md) ret+=query(rs,md+1,r,LL,RR); return ret;
}
#undef ls
#undef rs
}
#define ls (tr<<1)
#define rs (tr<<1|1)
int rt[N<<2];
struct node { int l,r,k; node() {}
node(int _l,int _r,int _k) {l=_l,r=_r,k=_k;}
}c[N];
int p,vl,d;
inline void change(int tr,int l,int r) {
Int::change(rt[tr],1,n,p,d); if(l==r) return ; R md=l+r>>1;
if(vl<=md) change(ls,l,md); if(vl>md) change(rs,md+1,r);
}
int LL,RR;
inline int query(int tr,int l,int r,int k) {
if(l==r) return l; R md=l+r>>1,tmp=0;
if(rt[ls]) tmp=Int::query(rt[ls],1,n,LL,RR);
if(tmp<k) return query(rs,md+1,r,k-tmp);
return query(ls,l,md,k);
}
inline void main() { //freopen("in.in","r",stdin); freopen("out.out","w",stdout);
n=g(),m=g(); for(R i=1;i<=n;++i) b[++cnt]=a[i]=g();
for(R i=1,l,r,k;i<=m;++i) {
register char ch; while(!isalpha(ch=getchar())); l=g(),r=g();
if(ch=='Q') k=g(),c[i]=node(l,r,k);
else c[i]=node(l,r,0),b[++cnt]=r;
} sort(b+1,b+cnt+1),cnt=unique(b+1,b+cnt+1)-b-1;
for(R i=1;i<=n;++i) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
for(R i=1;i<=m;++i) if(!c[i].k) c[i].r=lower_bound(b+1,b+cnt+1,c[i].r)-b;
d=1; for(R i=1;i<=n;++i) p=i,vl=a[i],change(1,1,cnt);
for(R i=1;i<=m;++i) {
if(c[i].k) LL=c[i].l,RR=c[i].r,printf("%d
",b[query(1,1,cnt,c[i].k)]);
else { p=c[i].l,vl=a[p],d=-1;
change(1,1,cnt),vl=a[p]=c[i].r,d=1,change(1,1,cnt);
}
}
}
} signed main() {Luitaryi::main(); return 0;}
整体二分
值域上整体二分,落实操作区间 ([LL,RR]) 中小于 (md) 的修改操作,扔到左边,大于 (md) 的修改忽略并扔到右边;并落实 ([LL,RR]) 中所有查询操作,若 (k) 比当前自己的排名大,那就把 (k) 剪掉当前的贡献,扔到右边,否则扔到左边。递归左边和右边。复杂度(O(nlog^2n))
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=100010,Inf=1e9;
int n,m,cnt,tot,ans[N],b[N],c[N];
struct node {int l,r,k,w,op; node() {}
node(int _l,int _r,int _k,int _w,int _op) {l=_l,r=_r,k=_k,w=_w,op=_op;}
} a[N*3],mem1[3*N],mem2[3*N];
inline void add(int p,int d) {for(;p<=n;p+=p&-p) c[p]+=d;}
inline int query(int p) { R ret=0;
for(;p;p-=p&-p) ret+=c[p]; return ret;
}
inline void solve(int l,int r,int LL,int RR) {
if(LL>RR) return ;
if(l==r) {for(R i=LL;i<=RR;++i) if(!a[i].op) ans[a[i].w]=l; return ;}
R md=l+r>>1,p=0,q=0;
for(R i=LL,tmp;i<=RR;++i) {
if(a[i].op) {
if(a[i].r<=md) add(a[i].l,a[i].w),mem1[++p]=a[i];
else mem2[++q]=a[i];
} else {
tmp=query(a[i].r)-query(a[i].l-1);
if(tmp<a[i].k) a[i].k-=tmp,mem2[++q]=a[i];
else mem1[++p]=a[i];
}
} for(R i=1;i<=p;++i) if(mem1[i].op) add(mem1[i].l,-mem1[i].w);
for(R i=1;i<=p;++i) a[LL-1+i]=mem1[i];
for(R i=1;i<=q;++i) a[LL-1+p+i]=mem2[i];
solve(l,md,LL,LL+p-1),solve(md+1,r,LL+p,RR);
}
inline void main() {
n=g(),m=g(); for(R i=1;i<=n;++i) b[i]=g(),a[++cnt]=node(i,b[i],0,1,1);
for(R i=1,l,r,k;i<=m;++i) { register char ch; while(!isalpha(ch=getchar()));
if(ch=='Q') l=g(),r=g(),k=g(),a[++cnt]=node(l,r,k,++tot,0);
else l=g(),r=g(),a[++cnt]=node(l,b[l],0,-1,1),a[++cnt]=node(l,r,0,1,1),b[l]=r;
} solve(1,Inf,1,cnt); for(R i=1;i<=tot;++i) printf("%d
",ans[i]);
}
} signed main() {Luitaryi::main(); return 0;}
2019.09.14
62