zoukankan      html  css  js  c++  java
  • 洛谷 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
    ",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
    ",a[ans]);
    		}
    	}
    	return 0;
    }
    
    
    

    平衡树

    先鸽着

  • 相关阅读:
    团队冲刺第四天
    团队冲刺第三天
    团队冲刺第二天
    冲刺(六)
    冲刺(五)
    冲刺(四)
    冲刺(三)
    冲刺(二)
    冲刺(一 )
    第一阶段SCRUM
  • 原文地址:https://www.cnblogs.com/zzhzzh123/p/12228211.html
Copyright © 2011-2022 走看看