1. 程式人生 > >[ZJOI2006] 書架

[ZJOI2006] 書架

query 一行 看書 bits play 排名 實現 整數 情況

[ZJOI2006]書架

題目描述

小T有一個很大的書櫃。這個書櫃的構造有些獨特,即書櫃裏的書是從上至下堆放成一列。她用1到n的正整數給每本書都編了號。

小T在看書的時候,每次取出一本書,看完後放回書櫃然後再拿下一本。由於這些書太有吸引力了,所以她看完後常常會忘記原來是放在書櫃的什麽位置。不過小T的記憶力是非常好的,所以每次放書的時候至少能夠將那本書放在拿出來時的位置附近,比如說她拿的時候這本書上面有X本書,那麽放回去時這本書上面就只可能有X-1、X或X+1本書。

當然也有特殊情況,比如在看書的時候突然電話響了或者有朋友來訪。這時候粗心的小T會隨手把書放在書櫃裏所有書的最上面或者最下面,然後轉身離開。

久而久之,小T的書櫃裏的書的順序就會越來越亂,找到特定的編號的書就變得越來越困難。於是她想請你幫她編寫一個圖書管理程序,處理她看書時的一些操作,以及回答她的兩個提問:(1)編號為X的書在書櫃的什麽位置;(2)從上到下第i本書的編號是多少。

輸入輸出格式

輸入格式:

第一行有兩個數n,m,分別表示書的個數以及命令的條數;第二行為n個正整數:第i個數表示初始時從上至下第i個位置放置的書的編號;第三行到m+2行,每行一條命令。命令有5種形式:

1. Top S——表示把編號為S的書放在最上面。

2. Bottom S——表示把編號為S的書放在最下面。

3. Insert S T——T∈{-1,0,1},若編號為S的書上面有X本書,則這條命令表示把這本書放回去後它的上面有X+T本書;

4. Ask S——詢問編號為S的書的上面目前有多少本書。

5. Query S——詢問從上面數起的第S本書的編號。

輸出格式:

對於每一條Ask或Query語句你應該輸出一行,一個數,代表詢問的答案。

輸入輸出樣例

輸入樣例#1:

10 10
1 3 2 7 5 8 10 4 9 6
Query 3
Top 5
Ask 6
Bottom 3
Ask 3
Top 6
Insert 4 -1
Query 5
Query 2
Ask 2

輸出樣例#1:

2
9
9
7
5
3

說明

100%的數據,\(n,m <= 80000\)

Solution

bzoj1861

對於書的順序,我們可以認為這些書有一個優先級,優先級越小代表它在書架中的順序越靠前,所以對於這些操作,其實就是要我們維護一個優先級

k小值??? 平衡樹!!!

本蒟蒻只會splay和(set/vector,,模擬平衡樹),所以在這裏擺上splay的做法


在這道題中,splay維護的不再是中序遍歷的結果,而是一個優先級

  1. Top s \(\to\)找到s在splay的編號,刪除後,將其優先級調道最小重新插入
  2. Bottom s \(\to\)和上面一樣,將優先級調到最大再插入
  3. Insert s,t \(\to\)將s和其前驅/後繼交換位置,實質是都刪除,交換優先級,再重新插入,比直接交換所有信息快的多
  4. Ask s \(\to\)查詢s的排名
  5. Query s \(\to\)查詢第s小值

那麽實際上如何操作呢?我們在讀入的時候,給每本書的編號x加一個id[x]=i,splay維護的就是這個id[]

那麽在插入的時候,我們就不能像之前那樣直接插入一個權值,而是要先找到它的優先級在splay中對應的節點在哪?再插入

void insert(int rank,int v) 
{
    int u=root,f=0;
    while(u && t[u].rk!=rank) {
        f=u;
        u=t[u].ch[rank>t[u].rk];
    }
    u=++tot;
    if(f) t[f].ch[rank>t[f].rk]=u;
    t[u].size=1; t[u].rk=rank;
    t[u].ch[0]=t[u].ch[1]=0;
    t[u].val=v,t[u].f=f;
    splay(u,0);
}

Insert操作如果懂了怎麽實現的話應該不用擺代碼了
Ask/Query是平衡樹基本操作
那麽直接上代碼了

提示:因為我們會不斷的刪除節點,而又沒有回收它的編號,所以在insert函數中,編號是一直在變大的,數組稍微開大點

Code

#include<bits/stdc++.h>
#define il inline
#define rg register
#define lol long long
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)

using namespace std;

const int N=2e5+10;
const int inf=2e9;

void in(int &ans)
{
    ans=0; int f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0', i=getchar();
    ans*=f;
}

int n,root,tot,m;
int minx,maxn;
int rk[N],id[N];

struct Splay {
    int f,size,ch[2],val,rk;
}t[N];

il bool get(int x) {
    return t[t[x].f].ch[1]==x;
}

il void up(int x) {
    t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
}

void rorate(int x) {
    int f=t[x].f,gf=t[f].f;
    int k1=get(x),k2=get(f);
    t[f].ch[k1]=t[x].ch[k1^1], t[t[x].ch[k1^1]].f=f;
    t[gf].ch[k2]=x, t[x].f=gf;
    t[f].f=x, t[x].ch[k1^1]=f;
    up(f); up(x);
}

void splay(int x,int goal) {
    while(t[x].f!=goal) {
        int f=t[x].f,gf=t[f].f;
        if(gf!=goal)
            (get(x)^get(f))?rorate(x):rorate(f);
        rorate(x);
    }
    if(!goal) root=x;
}

void insert(int rank,int v) {
    int u=root,f=0;
    while(u && t[u].rk!=rank) {
        f=u;
        u=t[u].ch[rank>t[u].rk];
    }
    u=++tot;
    if(f) t[f].ch[rank>t[f].rk]=u;
    t[u].size=1; t[u].rk=rank;
    t[u].ch[0]=t[u].ch[1]=0;
    t[u].val=v,t[u].f=f;
    splay(u,0);
}

void find(int rank) {
    int u=root; if(!u) return;
    while(t[u].ch[rank>t[u].rk] && rank!=t[u].rk)
        u=t[u].ch[rank>t[u].rk];
    splay(u,0);
}

int kth(int k) {
    int u=root; if(t[u].size<k) return 0;
    while(1) {
        int y=t[u].ch[0];
        if(k>t[y].size+1) {
            k-=t[y].size+1;
            u=t[u].ch[1];
        }
        else if(k<=t[y].size) u=y;
        else return t[u].val;
    }
}

int Rank(int x) {
    find(x); int u=root;
    return t[t[u].ch[0]].size+1;
}

int Get(int rank,int f) {
    find(rank); int u=root;
    if(t[u].rk>rank && f) return u;
    if(t[u].rk<rank && !f) return u;
    u=t[u].ch[f];
    while(t[u].ch[f^1]) u=t[u].ch[f^1];
    return u;
}

void Del(int x) {
    int last=Get(x,0),nex=Get(x,1);
    splay(last,0); splay(nex,last);
    t[nex].ch[0]=0;
}

void work(int x,int f) {
    find(id[x]);
    int v=t[root].val; Del(id[x]);
    if(!f) id[x]=--minx,insert(id[x]=--minx,v);
    else insert(id[x]=++maxn,v);
}

void sp(int x,int f) {
    if(!f) return;
    int rk1=Rank(id[x]),rk2=rk1+f;
    int v1=x,v2=kth(rk2);
    Del(id[v1]); Del(id[v2]);
    swap(id[v1],id[v2]);
    insert(id[v1],v1); insert(id[v2],v2);
}

il void Ask(int x) {
    find(id[x]); int u=root;
    printf("%d\n",t[t[u].ch[0]].size-1);
}

il void Query(int x) {
    printf("%d\n",kth(x+1));
}

int main()
{
    in(n); in(m);
    minx=1,maxn=n; int x,y;
    insert(inf,inf); insert(-inf,-inf);
    for(int i=1;i<=n;i++) in(x),insert(id[x]=i,x);
    for(int i=1;i<=m;i++) {
        char s[10]; scanf("%s",s);
        if(s[0]=='T') in(x),work(x,0);
        if(s[0]=='B') in(x),work(x,1);
        if(s[0]=='I') in(x),in(y),sp(x,y);
        if(s[0]=='A') in(x),Ask(x);
        if(s[0]=='Q') in(x),Query(x);
    }
    return 0;
}

博主蒟蒻,隨意轉載.但必須附上原文鏈接

http://www.cnblogs.com/real-l/

[ZJOI2006] 書架