题目大意:有一个书架,现在需要经常改变这些书的位置,每次询问一本书在哪或者第几本书是什么。
思路:赤裸裸的Splay,只是有些小事需要注意。因为他有的时候问你一个书在哪,这个事情不能只在Splay中就能解决,我们需要辅助他解决。注意到操作中没有加入书的操作,也就是书的总数并不会变化,而且Splay的过程中只是指针的变动,所以不会有点发生变化,所以在一开始建树的时候维护一个数组,表示这本书在Splay中的节点,这样我们就能快速的找到任意一本书的节点。询问一本书的排名的时候,我们需要先找到这个节点,然后不断向根靠近,在这过程中进行统计有多少个节点在这个节点前面就行了。自己YY出来的思路,不过感觉这种操作不是Splay原生的操作,应该还有更优雅的解决方法吧。。具体见代码。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 80010 using namespace std; struct SplayTree{ int val,size; SplayTree *son[2],*father; bool Check() { return father->son[1] == this; } void Combine(SplayTree *a,bool dir) { a->father = this; son[dir] = a; } }*pos[MAX],none,*nil = &none,*root; int points,asks; int src[MAX]; char s[10]; SplayTree *NewNode(int _) { SplayTree *re = new SplayTree(); re->son[0] = re->son[1] = nil; re->val = _; re->size = 1; return re; } inline void PushUp(SplayTree *a) { a->size = a->son[0]->size + a->son[1]->size + 1; } SplayTree *BuildTree(int l,int r) { if(l > r) return nil; int mid = (l + r) >> 1; SplayTree *re = NewNode(src[mid]); pos[src[mid]] = re; re->Combine(BuildTree(l,mid - 1),false); re->Combine(BuildTree(mid + 1,r),true); PushUp(re); return re; } inline void Rotate(SplayTree *&a,bool dir) { SplayTree *f = a->father; f->son[!dir] = a->son[dir]; f->son[!dir]->father = f; a->son[dir] = f; f->father->son[f->Check()] = a; a->father = f->father; f->father = a; PushUp(f); if(root == f) root = a; } inline void Splay(SplayTree *a,SplayTree *aim) { while(a->father != aim) { if(a->father->father == aim) Rotate(a,!a->Check()); else if(!a->father->Check()) { if(!a->Check()) Rotate(a->father,true),Rotate(a,true); else Rotate(a,false),Rotate(a,true); } else { if(a->Check()) Rotate(a->father,false),Rotate(a,false); else Rotate(a,true),Rotate(a,false); } } PushUp(a); } SplayTree *Find_(SplayTree *a,int k) { if(k <= a->son[0]->size) return Find_(a->son[0],k); k -= a->son[0]->size; if(k == 1) return a; return Find_(a->son[1],k - 1); } int Find(SplayTree *a,int k) { if(k <= a->son[0]->size) return Find(a->son[0],k); k -= a->son[0]->size; if(k == 1) return a->val; return Find(a->son[1],k - 1); } inline int Rank(SplayTree *a) { int re = a->son[0]->size; while(a != root) { if(a->Check()) re += a->father->son[0]->size + 1; a = a->father; } return re + 1; } inline void Insert(int rank,int aim) { Splay(Find_(root,rank - 1),nil); Splay(Find_(root,rank + 1),root); SplayTree *temp = root->son[1]->son[0]; root->son[1]->son[0] = nil; PushUp(root->son[1]); PushUp(root); Splay(Find_(root,aim - 1),nil); Splay(Find_(root,aim),root); root->son[1]->Combine(temp,false); PushUp(root->son[1]); PushUp(root); } int main() { cin >> points >> asks; for(int i = 1; i <= points; ++i) scanf("%d",&src[i]); root = BuildTree(0,points + 1); root->father = nil; nil->son[1] = root; nil->son[0] = nil; for(int x,y,i = 1; i <= asks; ++i) { scanf("%s",s); if(s[0] == 'Q') { scanf("%d",&x); printf("%d\n",Find(root,x + 1)); } if(s[0] == 'A') { scanf("%d",&x); printf("%d\n",Rank(pos[x]) - 2); } if(s[0] == 'T') { scanf("%d",&x); int rank = Rank(pos[x]); Insert(rank,2); } if(s[0] == 'B') { scanf("%d",&x); int rank = Rank(pos[x]); Insert(rank,points + 1); } if(s[0] == 'I') { scanf("%d%d",&x,&y); if(!y) continue; int rank = Rank(pos[x]),temp; if(y == 1) temp = rank + 1; else temp = rank - 1; Insert(rank,temp); } } return 0; }
时间: 2024-10-17 08:47:21