P2617 Dynamic Rankings
Posted jackpei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2617 Dynamic Rankings相关的知识,希望对你有一定的参考价值。
思路:数据结构
提交: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 queint 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\n",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\n",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\n",ans[i]);
signed main() Luitaryi::main(); return 0;
2019.09.14
62
以上是关于P2617 Dynamic Rankings的主要内容,如果未能解决你的问题,请参考以下文章