洛谷 P2596 [ZJOI2006]书架 解题报告
P2596 [ZJOI2006]書架
題目描述
小T有一個(gè)很大的書柜。這個(gè)書柜的構(gòu)造有些獨(dú)特,即書柜里的書是從上至下堆放成一列。她用1到n的正整數(shù)給每本書都編了號(hào)。
小T在看書的時(shí)候,每次取出一本書,看完后放回書柜然后再拿下一本。由于這些書太有吸引力了,所以她看完后常常會(huì)忘記原來是放在書柜的什么位置。不過小T的記憶力是非常好的,所以每次放書的時(shí)候至少能夠?qū)⒛潜緯旁谀贸鰜頃r(shí)的位置附近,比如說她拿的時(shí)候這本書上面有X本書,那么放回去時(shí)這本書上面就只可能有X-1、X或X+1本書。
當(dāng)然也有特殊情況,比如在看書的時(shí)候突然電話響了或者有朋友來訪。這時(shí)候粗心的小T會(huì)隨手把書放在書柜里所有書的最上面或者最下面,然后轉(zhuǎn)身離開。
久而久之,小T的書柜里的書的順序就會(huì)越來越亂,找到特定的編號(hào)的書就變得越來越困難。于是她想請(qǐng)你幫她編寫一個(gè)圖書管理程序,處理她看書時(shí)的一些操作,以及回答她的兩個(gè)提問:(1)編號(hào)為X的書在書柜的什么位置;(2)從上到下第i本書的編號(hào)是多少。
輸入輸出格式
輸入格式:
第一行有兩個(gè)數(shù)n,m,分別表示書的個(gè)數(shù)以及命令的條數(shù);第二行為n個(gè)正整數(shù):第i個(gè)數(shù)表示初始時(shí)從上至下第i個(gè)位置放置的書的編號(hào);第三行到m+2行,每行一條命令。命令有5種形式:
1. Top S——表示把編號(hào)為S的書放在最上面。
2. Bottom S——表示把編號(hào)為S的書放在最下面。
3. Insert S T——T∈{-1,0,1},若編號(hào)為S的書上面有X本書,則這條命令表示把這本書放回去后它的上面有X+T本書;
4. Ask S——詢問編號(hào)為S的書的上面目前有多少本書。
5. Query S——詢問從上面數(shù)起的第S本書的編號(hào)。
輸出格式:
對(duì)于每一條Ask或Query語句你應(yīng)該輸出一行,一個(gè)數(shù),代表詢問的答案。
說明
100%的數(shù)據(jù),n,m <= 80000
這是我做的第一道非板子的平衡樹題目,寫+調(diào)大概花了2個(gè)小時(shí),稍稍有點(diǎn)困,先以時(shí)間壓到1個(gè)小時(shí)為目標(biāo)了。
很顯然,這顆平衡樹是一顆區(qū)間樹,用來平衡的域是書的相對(duì)位置大小,我們用樹的大小信息來查詢某個(gè)點(diǎn)在書架的相對(duì)位置,而不去直接存儲(chǔ)這個(gè)相對(duì)位置以比較,這應(yīng)該是區(qū)間樹的一個(gè)重要特點(diǎn)。
用\(pos[i]\)維護(hù)編號(hào)為\(i\)的書對(duì)應(yīng)哪個(gè)節(jié)點(diǎn)。
對(duì)于操作:
放在最上面/下面就先刪掉然后加點(diǎn)
添加的話只有兩個(gè)情況,就先把要添加的節(jié)點(diǎn)伸展到根,然后和它的前驅(qū)/后繼交換即可
兩個(gè)詢問互為逆操作,有關(guān)排名的
#include <cstdio> #include <iostream> #define ls t[now].ch[0] #define rs t[now].ch[1] #define f t[now].par #define s t[now].ch[typ] using namespace std; const int N=160010; struct Splay {int ch[2],par,siz,num; }t[N]; int root,tot=0,n,m,x,a[N],pos[N];//編號(hào)為i的書對(duì)應(yīng)的當(dāng)前點(diǎn)的編號(hào) string S; int identity(int now) {return t[f].ch[1]==now; } void connect(int fa,int now,int typ) {f=fa;t[fa].ch[typ]=now; } void updata(int now) {t[now].siz=t[ls].siz+t[rs].siz+1; } void rotate(int now) {int p=f,typ=identity(now);connect(p,t[now].ch[typ^1],typ);connect(t[p].par,now,identity(p));connect(now,p,typ^1);updata(p),updata(now); } void splay(int now,int to) {to=t[to].par;for(int typ;f!=to;rotate(now))if(t[f].par!=to)rotate(identity(now)==identity(f)?f:now);if(!to) root=now; } int New(int dat) {t[++tot].num=dat;t[tot].siz=1;return tot; } void free(int now) {t[now].num=0;t[now].siz=0;t[now].par=0;ls=0;rs=0;if(tot==now) tot--; } void find(int x)//當(dāng)前排名為x的書的編號(hào) {int now=root;while(t[ls].siz+1!=x)now=t[now].ch[t[ls].siz+1<x?x-=t[ls].siz+1,1:0];splay(now,root);printf("%d\n",t[now].num); } int get_max(int now,int typ) {if(typ) t[now].siz++;return rs?get_max(rs,typ):now; } int get_min(int now,int typ) {if(typ) t[now].siz++;return ls?get_min(ls,typ):now; } void extrack(int now)//刪除編號(hào)為now的點(diǎn) {splay(now,root);if(!ls){root=rs;connect(0,root,1);free(now);return;}int rt=get_max(ls,0);splay(rt,ls);connect(rt,rs,1);connect(0,rt,1);updata(rt);root=rt;free(now); } void rank(int now) {splay(now,root);printf("%d\n",t[ls].siz); } void top(int now,int num)//節(jié)點(diǎn)編號(hào)和書的編號(hào) {extrack(now);int fa=get_min(root,1);connect(fa,now=New(num),0);pos[num]=now;updata(now); } void bottom(int now,int num) {extrack(now);int fa=get_max(root,1);connect(fa,now=New(num),1);pos[num]=now;updata(now); } void exchange(int to,int now) {swap(pos[t[to].num],pos[t[now].num]);swap(t[to].num,t[now].num); } void insert(int now,int T) {if(!T) return;splay(now,root);if(T==1) exchange(get_min(rs,0),now);else exchange(get_max(ls,0),now); } int build(int l,int r,int fa) {if(l>r) return 0;int now=l+r>>1;t[now].par=fa;t[now].num=a[now];updata(now);if(l==r) return now;ls=build(l,now-1,now);rs=build(now+1,r,now);updata(now);return now; } /*void write(int now) {if(!now) return;write(ls);printf("%d ",t[now].num);write(rs); }*/ int main() {scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",a+i);pos[a[i]]=i;}connect(0,root=build(1,n,0),1);tot=n;for(int i=1;i<=m;i++){cin>>S;scanf("%d",&x);if(S=="Top")top(pos[x],x);else if(S=="Bottom")bottom(pos[x],x);else if(S=="Insert"){int T;scanf("%d",&T);insert(pos[x],T);}else if(S=="Ask")rank(pos[x]);elsefind(x);//write(root);//printf("%d\n");}return 0; }
2018.6.14
轉(zhuǎn)載于:https://www.cnblogs.com/butterflydew/p/9182269.html
總結(jié)
以上是生活随笔為你收集整理的洛谷 P2596 [ZJOI2006]书架 解题报告的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java开发手册归纳知识点
- 下一篇: 洛谷 P2084 进制转换