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的主要内容,如果未能解决你的问题,请参考以下文章

bzoj P2617 Dynamic Rankings

P2617 Dynamic Rankings

P2617 Dynamic Rankings

P2617 Dynamic Rankings(整体二分)

P2617 Dynamic Rankings(带修主席树)

P2617 Dynamic Ranking