这个礼拜准备把Splay树补完,这道题被认为是一道Splay的水题,(然而像我这种入门级学习后还是搞了好久,毕竟算是第一次接触吧)。
感觉Splay树必须要明确的一点:该树的中序遍历就是现在的序列
这里面有一个区间翻转的操作,涉及到区间问题,Splay树的核心就是RotateTo(l-1,0),Rotate(r+1,root),就是把该区间的前一个数转到根节点,后一个数转到根节点的右节点,这是Key_Tree = ch[ch[root][1]][0]代表的就是这段区间。因为Splay树并不是线段树(非叶子节点可以代表一个区间)。Splay树的每个节点都是一个点,所以我们除了维护点的值外,我们还要维护以该点为根的子树的值(对应的也就是区间值)。
我们在原序列两端添加两个节点。
本题的关键就是找到第i小的点以后要把该段区间翻转以后删掉第i小的点(因为后面的操作和找到的点已经没有关系了)。然后delete操作怎么写?
我们假设当前要寻找原序列中的第i小的点,由于我们前i-1小的点都已经删除了,所以我们只需要找当前序列的第i小的点,然后把这个节点转到ch[root][1],然后我们找这个节点的前驱。转到该节点下方,然后删掉该节点。就可以了。(具体看代码)。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #define LL long long #define FOR(i,x,y) for(int i = x;i < y;i ++) #define IFOR(i,x,y) for(int i = x;i > y;i --) #define Key_Tree ch[ch[root][1]][0] #define MAXN 110000 using namespace std; int id[MAXN],n,p[MAXN],pos[MAXN]; struct Num{ int num; int id; bool operator < (const Num& rhs) const{ if(num == rhs.num) return id < rhs.id; return num < rhs.num; } }st[MAXN]; struct SplayTree{ int ch[MAXN][2],sz[MAXN],pre[MAXN],key[MAXN],root,tot; int flip[MAXN]; void Rotate(int x,int kind){ int y = pre[x]; Push_Down(y); Push_Down(x); ch[y][!kind] = ch[x][kind]; pre[ch[x][kind]] = y; if(pre[y]){ ch[pre[y]][ch[pre[y]][1] == y] = x; } pre[x] = pre[y]; ch[x][kind] = y; pre[y] = x; Push_Up(y); } void Splay(int x,int goal){ Push_Down(x); while(pre[x] != goal){ Push_Down(pre[pre[x]]); Push_Down(pre[x]); Push_Down(x); if(pre[pre[x]] == goal){ Rotate(x,ch[pre[x]][0] == x); } else{ int y = pre[x]; int kind = (ch[pre[y]][0] == y); if(ch[y][kind] == x){ Rotate(x,!kind); Rotate(x,kind); } else{ Rotate(y,kind); Rotate(x,kind); } } } Push_Up(x); if(!goal) root = x; } void RotateTo(int k,int goal){ int x = root; Push_Down(x); while(sz[ch[x][0]] != k){ if(k < sz[ch[x][0]]){ x = ch[x][0]; } else{ k -= (sz[ch[x][0]]+1); x = ch[x][1]; } Push_Down(x); } Splay(x,goal); } //debug部分copy from hh void Treaval(int x) { if(x) { Treaval(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d ",x,ch[x][0],ch[x][1],pre[x],sz[x],key[x]); Treaval(ch[x][1]); } } void debug() {printf("%d ",root);Treaval(root);} //以上debug void NewNode(int& x,int father,int k){ x = ++tot; pre[x] = father; key[x] = k; ch[x][0] = ch[x][1] = 0; sz[x] = 1; flip[x] = 0; } void Push_Up(int x){ sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } void Push_Down(int x){ if(flip[x]){ flip[ch[x][0]] ^= 1; flip[ch[x][1]] ^= 1; flip[x] = 0; swap(ch[x][1],ch[x][0]); } } void Build(int& x,int l,int r,int father){ if(l > r) return; int mid = (l+r) >> 1; NewNode(x,father,p[mid]); pos[mid+1] = x; Build(ch[x][0],l,mid-1,x); Build(ch[x][1],mid+1,r,x); Push_Up(x); } void Init(){ root = tot = 0; ch[0][1] = ch[0][0] = pre[0] = sz[0] = 0; NewNode(root,0,0); NewNode(ch[root][1],root,0); sz[root] = 2; Build(Key_Tree,0,n-1,ch[root][1]); Push_Up(ch[root][1]); Push_Up(root); } void del(){ int x = Get_Pre(ch[root][1]); if(x == -1){ pre[ch[ch[root][1]][1]] = root; ch[root][1] = ch[ch[root][1]][1]; } else{ Splay(x,ch[root][1]); pre[Key_Tree] = root; pre[ch[ch[root][1]][1]] = Key_Tree; ch[Key_Tree][1] = ch[ch[root][1]][1]; ch[root][1] = Key_Tree; } } void solve(){ FOR(i,1,n+1){ //debug(); Splay(1,0); Splay(id[i],root); flip[Key_Tree] ^= 1; if(i == 1){printf("%d",i+sz[Key_Tree]);} else printf(" %d",i+sz[Key_Tree]); del(); } printf(" "); } int Get_Pre(int x){ Push_Down(x); x = ch[x][0]; while(x){ Push_Down(x); while(ch[x][1]){ x = ch[x][1]; Push_Down(x); } return x; } return -1; } int Get_Next(int x){ Push_Down(x); x = ch[x][1]; while(x){ Push_Down(x); while(ch[x][0]){ x = ch[x][0]; Push_Down(x); } return x; } return -1; } }spt; int main() { //freopen("test.in","r",stdin); while(~scanf("%d",&n) && n){ FOR(i,0,n) {scanf("%d",&st[i].num); p[i] = st[i].num; st[i].id = i+1;} spt.Init(); //spt.debug(); sort(st,st+n); FOR(i,1,n+1){ id[i] = pos[st[i-1].id]; } spt.solve(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。