zoukankan      html  css  js  c++  java
  • 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 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

  • 相关阅读:
    Context都没弄明白,还怎么做Android开发?
    Android中Drawable分类汇总
    查找首个非重复字符
    七个对我最好的职业建议(译文)
    Android:最全面的 Webview 详解
    Android开发之微信底部菜单栏实现的几种方法汇总
    android 底部菜单栏实现(转)
    Android实现顶部底部双导航界面功能
    Android BottomNavigationBar底部导航控制器的使用
    Android底部导航栏的四种实现
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11518251.html
Copyright © 2011-2022 走看看