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\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

posted @ 2019-09-14 07:42  LuitaryiJack  阅读(216)  评论(0编辑  收藏  举报