洛谷 P2596 [ZJOI2006]书架

题目链接

本题目有两种做法:平衡树和树状数组

其实这两种做法有异曲同工之妙

树状数组

我们在原来的数组两端分别再接一段数组

变成:

\(_,_,_,_,_,_,_,_,_,_,1,3,2,7,5,8,10,4,9,6,_,_,_,_,_,_,_,_,_,_\)

我们维护两个信息 ,Pos数组和a数组

Pos[i]表示编号为i的书对应在上面的数组的下标

a[i]表示上面数组第i位书对应的编号

再维护一个树状数组

其前缀和S[i]表示上面数组前i位上共有几本书

Top操作

例:Top 7

\(_,_,_,_,_,_,_,_,_,_,1,3,2,7,5,8,10,4,9,6,_,_,_,_,_,_,_,_,_,_\)

\(_,_,_,_,_,_,_,_,_,7,1,3,2,_,5,8,10,4,9,6,_,_,_,_,_,_,_,_,_,_\)

Bottom操作

例:Bottom 4

\(_,_,_,_,_,_,_,_,_,_,1,3,2,7,5,8,10,4,9,6,_,_,_,_,_,_,_,_,_,_\)

\(_,_,_,_,_,_,_,_,_,_,1,3,2,7,5,8,10,_,9,6,4,_,_,_,_,_,_,_,_,_\)

以上两种操作本质一样

我们用两个变量l,r来记录书的所在位置的范围,每次操作就是将原来的书本取出,放在左端点左边或右端点右边

然后--l或++r

Ask操作

答案即为query(Pos[s])-1

query为树状数组查询函数

Query操作

有点麻烦,我们采用二分套查询的方法 \(O(log^2n)\)解决问题

首先S数组为前缀和数组,其值具有单调性,若S[i]=s&&S[i-1]=s-1,则i即为第s本书所在位置,答案即为a[i]

在l,r的范围内二分,每次用query(i)获取S[i]

最后就能得到答案

Insert操作

相当于是交换前后两本书,我们考虑直接找到另一本书,swap二者的对应数组的值即可

Insert s t

t=0直接continue

否则先找到编号为s的书是第几本 sNum 等同于Ask操作

然后得到另一本书是第几本tNum=sNum+t

然后得到另一本书的位置 tPos 等同于Query操作

最后得到两本书的所有信息

编号s||位置sPos=Pos[s]||第几本sNum

编号tId=a[tPos]||位置tPos||第几本tNum

更新(swap) a[sPos]和a[tPos],Pos[s]和Pos[tId]

小心一个swap后,其值就变了,不能用来定位另一个值,第二个swap会出错

[Code]


#include <bits/stdc++.h>
using namespace std;

int read(){
	int x=0,flag=1; char c;
	for(c=getchar();!isdigit(c);c=getchar()) if(c=='-') flag=-1;
	for(;isdigit(c);c=getchar()) x=((x+(x<<2))<<1)+(c^48);
	return x*flag;
}

const int N=250000;
const int gap=80005;
int n,m;

int c[N];
int lowbit(int x) { return x&(-x); }
int query(int x){
	int ret=0;
    for(int i=x;i>0;i-=lowbit(i)) ret+=c[i];
    return ret;
}
void update(int x,int y){
    for(int i=x;i<=250000;i+=lowbit(i)) c[i]+=y;
}

int pos[N],a[N];
int l,r;

int main() {
    n=read(),m=read();
    
    for(int i=1;i<=n;i++){
	    int x=read();
	    pos[x]=i+gap;
	    a[i+gap]=x; 
	    update(i+gap,1);
	}
	
	l=gap+1; r=gap+n;
	while(m--){
		
	    char s[15];
	    int x,y;
	    scanf(" %s %d",s,&x);
	    
	    if(s[0]=='T'){
		    update(pos[x],-1);
		    a[pos[x]]=0;
		    
		    pos[x]=--l; update(pos[x],1);
		    a[pos[x]]=x;
		}
		
		if(s[0]=='B'){
		    update(pos[x],-1);
		    a[pos[x]]=0;
		    
		    pos[x]=++r; update(pos[x],1);
		    a[pos[x]]=x;
		}
		
		if(s[0]=='I'){
			int y=read();
			if(y==0) continue;
			
			int z=query(pos[x])+y;
			
		    int ll=l,rr=r,ans=-1;
		    while(ll<=rr){
			    int mid=(ll+rr)>>1;
			    if(query(mid)>=z) { rr=mid-1; ans=mid; }
			    else ll=mid+1;
			}
			
			int p=pos[x];
			swap(pos[a[ans]],pos[x]); 
			swap(a[p],a[ans]);
		}
		
		if(s[0]=='A'){
		    printf("%d\n",query(pos[x])-1);
		}
		if(s[0]=='Q'){
		    int ll=l,rr=r,ans=-1;
		    while(ll<=rr){
			    int mid=(ll+rr)>>1;
			    if(query(mid)>=x) { rr=mid-1; ans=mid; }
			    else ll=mid+1;
			}
			printf("%d\n",a[ans]);
		}
	}
	return 0;
}


平衡树

先鸽着

posted @ 2020-01-22 11:25  zhuzihan  阅读(107)  评论(0编辑  收藏  举报