P2596 [ZJOI2006]书架
Posted FJOI
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2596 [ZJOI2006]书架相关的知识,希望对你有一定的参考价值。
\\(\\colorpurple\\textP2596 [ZJOI2006]书架\\)
解题方法
考虑使用 \\(\\textFHQ\\) 平衡树 ,我们只使用编号,而不使用权值,平衡树上的先序遍历即为书的放置顺序。
- \\(\\textQuery\\) :这是最简单的操作,直接查询即可。
- \\(\\textAsk\\):本题的核心,我们知道编号,因为没有权值,没法从根往下找到询问点,如果强制设权值会很麻烦。正难则反,既然我们知道询问点的编号,不如从询问点向上走回根,这个操作需要我们维护每个节点的父亲。(记得每次树改变时把根的父亲设为 \\(0\\) )
- \\(\\textBottom/Top/Insert\\) 既然已经有了 \\(Ask\\) ,我们可以直接通过编号找到排名,继而分裂出需要改变的点,剩下的就是重新组合。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+110;
int read()
int x=0,f=1;char c=getchar();
while(c>\'9\' || c<\'0\')if(c==\'-\')f=-1;c=getchar();
while(c>=\'0\' && c<=\'9\')x=(x<<1)+(x<<3)+(c^48);c=getchar();
return x*f;
int n,m,rl[N],fx[N];
struct FHQ
int rt,x,y,z,cnt,phi;
int ls[N],rs[N],rad[N],sze[N];
int fa[N];
void pushup(int u)sze[u]=sze[ls[u]]+sze[rs[u]]+1;return;
int newnode()
rad[++cnt]=rand();
sze[cnt]=1;
return cnt;
void split(int u,int k,int &x,int &y,int fax,int fay)
if(!u)x=0,y=0;
else
if(k>sze[ls[u]])
x=u;fa[u]=fax;
split(rs[u],k-sze[ls[u]]-1,rs[u],y,u,fay);
else
y=u;fa[u]=fay;
split(ls[u],k,x,ls[u],fax,u);
pushup(u);
return;
int merge(int A,int B)
if(!A || !B)return A+B;
if(rad[A]<rad[B])rs[A]=merge(rs[A],B);fa[rs[A]]=A;pushup(A);return A;
else ls[B]=merge(A,ls[B]);fa[ls[B]]=B;pushup(B);return B;
void insert()rt=merge(rt,newnode());return;
int Query(int k)
split(rt,k,x,z,0,0);
split(x,k-1,x,y,fa[x],fa[y]);
int tmp=y;rt=merge(merge(x,y),z);fa[rt]=0;
return tmp;
int ask(int x,int fr)
if(x==0)return 0;
if(fr==ls[x])return ask(fa[x],x);
else return ask(fa[x],x)+sze[ls[x]]+1;
int Ask(int x)return ask(fa[x],x)+sze[ls[x]];
void top(int k)
split(rt,k-1,x,y,fa[x],fa[y]);
split(y,1,y,z,fa[y],fa[z]);
rt=merge(y,merge(x,z));fa[rt]=0;
void bottom(int k)
split(rt,k-1,x,y,fa[x],fa[y]);
split(y,1,y,z,fa[y],fa[z]);
rt=merge(merge(x,z),y);fa[rt]=0;
void sap(int k,int t)
if(t==-1)
split(rt,k-2,x,y,fa[x],fa[y]);
split(y,1,y,z,fa[y],fa[z]);
split(z,1,z,phi,fa[z],fa[phi]);
rt=merge(merge(x,z),merge(y,phi));fa[rt]=0;
if(t==1)
split(rt,k-1,x,y,fa[x],fa[y]);
split(y,1,y,z,fa[y],fa[z]);
split(z,1,z,phi,fa[z],fa[phi]);
rt=merge(merge(x,z),merge(y,phi));fa[rt]=0;
return;
void sd(int u)
if(!u)return;
cout<<u<<" "<<sze[u]<<" "<<ls[u]<<" "<<rs[u]<<" "<<fa[u]<<endl;
sd(ls[u]);
sd(rs[u]);
void Bark()
printf("-----------HYC is here-----------\\n");
sd(rt);
printf("-----------HYC has gone-----------\\n");
T;
int main()
srand(20230502);
n=read(),m=read();
for(int i=1;i<=n;i++)rl[i]=read(),fx[rl[i]]=i;//树编号-》实际编号;实际编号-》树编号
for(int i=1;i<=n;i++)T.insert();
// T.Bark();
for(int i=1;i<=m;i++)
char opt[10];scanf("%s",opt);
if(opt[0]==\'Q\')int k=read();printf("%d\\n",rl[T.Query(k)]);
if(opt[0]==\'A\')int x=read();printf("%d\\n",T.Ask(fx[x]));
if(opt[0]==\'T\')int x=read();T.top(T.Ask(fx[x])+1);
if(opt[0]==\'B\')int x=read();T.bottom(T.Ask(fx[x])+1);
if(opt[0]==\'I\')int x=read(),t=read();T.sap(T.Ask(fx[x])+1,t);
// T.Bark();
return 0;
BZOJ 1861: [Zjoi2006]Book 书架 (splay)
1861: [Zjoi2006]Book 书架
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1453 Solved: 822
[Submit][Status][Discuss]
Description
小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。 当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。 久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。
Input
第一行有两个数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本书的编号。
Output
对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。
Sample Input
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
Sample Output
9
9
7
5
3
HINT
数据范围
Source
————————————————————————
splay维护序列的裸题
只需要维护一个子树大小size
1.top 将一个点删除,插入到根节点最左儿子
2.bottom 将一个点删除,插入到根节点最右儿子
3.insert +1 -1 (记录s前一个点为prev,后一个点为next)
-1 prev提根,s插在prev和它的左儿子之间
+1 next提根,s插在next和它的右儿子之间
4.ask s提根,左儿子的size
5.query 递归查找即可
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <set> 7 #include <vector> 8 #include <string.h> 9 #define siji(i,x,y) for(int i=(x);i<=(y);++i) 10 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j) 11 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i) 12 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j) 13 #define inf 0x1f1f1f1f 14 #define ivorysi 15 #define mo 97797977 16 #define hash 974711 17 #define base 47 18 #define MAXN 100005 19 #define fi first 20 #define se second 21 #define pii pair<int,int> 22 using namespace std; 23 typedef long long ll; 24 struct node { 25 int size,son[2],fa; 26 void clear() { 27 size=son[0]=son[1]=fa=0; 28 } 29 }tree[MAXN]; 30 int root; 31 //维护size 32 void update(int x,int c) { 33 int k=tree[x].size; 34 int o=tree[x].fa; 35 tree[x].size=tree[o].size; 36 tree[o].size=tree[o].size-k+tree[tree[x].son[c]].size; 37 } 38 void rotate(int x,int c) { 39 update(x,c); 40 int o=tree[x].fa; 41 if(tree[o].fa!=0) { 42 int t= o==tree[tree[o].fa].son[0] ? 0 : 1; 43 tree[tree[o].fa].son[t]=x; 44 } 45 tree[o].son[c^1]=tree[x].son[c]; 46 if(tree[o].son[c^1])tree[tree[o].son[c^1]].fa=o; 47 tree[x].son[c]=o; 48 tree[x].fa=tree[o].fa; 49 tree[o].fa=x; 50 51 } 52 void splay(int x,int y) { 53 while(tree[x].fa!=y) { 54 int k1= x==tree[tree[x].fa].son[0] ? 1 : 0; 55 int k2= tree[x].fa == tree[tree[tree[x].fa].fa].son[0] ? 1 : 0; 56 if(tree[tree[x].fa].fa!=y && k2==k1) { 57 rotate(tree[x].fa,k1); 58 rotate(x,k1); 59 } 60 else { 61 rotate(x,k1); 62 } 63 } 64 if(y==0) root=x; 65 else { 66 67 } 68 } 69 int find(int x,int c) { 70 splay(x,0); 71 int t=tree[x].son[c]; 72 while(tree[t].son[c^1]!=0) { 73 t=tree[t].son[c^1]; 74 } 75 return t; 76 } 77 void delete_x(int prev,int next) { 78 if(prev!=0 && next!=0) { 79 splay(prev,0); 80 splay(next,prev); 81 tree[tree[root].son[1]].son[0]=0; 82 --tree[tree[root].son[1]].size; 83 } 84 else if(prev!=0) { 85 splay(prev,0); 86 tree[root].son[1]=0; 87 } 88 else { 89 splay(next,0); 90 tree[root].son[0]=0; 91 } 92 --tree[root].size; 93 } 94 //0是top 1是bottom 95 void in_hurry(int x,int c) { 96 int pr=find(x,0),ne=find(x,1); 97 delete_x(pr,ne); 98 int t=root; 99 ++tree[t].size; 100 tree[x].son[c^1]=tree[t].son[c]; 101 tree[tree[t].son[c]].fa=x; 102 tree[x].size=tree[tree[t].son[c]].size+1; 103 tree[x].fa=t; 104 tree[t].son[c]=x; 105 } 106 int ask(int x) { 107 splay(x,0); 108 return tree[tree[x].son[0]].size; 109 } 110 void insert(int x,int c) { 111 if(c==0) return; 112 if(ask(x)==0 && c==-1) return; 113 int pr=find(x,0),ne=find(x,1); 114 delete_x(pr,ne); 115 int t= c==-1 ? pr : ne; 116 splay(t,0); 117 c= c==-1 ? 0 : 1; 118 ++tree[t].size; 119 tree[x].clear(); 120 tree[x].son[c]=tree[t].son[c]; 121 tree[tree[t].son[c]].fa=x; 122 tree[x].size=tree[tree[t].son[c]].size+1; 123 tree[t].son[c]=x; 124 tree[x].fa=t; 125 splay(x,0); 126 } 127 128 void query(int x,int s) { 129 int temp=tree[tree[x].son[0]].size+1; 130 if(s==temp) {splay(x,0);return;} 131 int t=s<temp ? 0 : 1; 132 s = s>=temp ? s-temp : s; 133 query(tree[x].son[t],s); 134 } 135 int n,m; 136 void init() { 137 scanf("%d%d",&n,&m); 138 int a=0,b; 139 siji(i,1,n) { 140 scanf("%d",&b); 141 tree[b].fa=a; 142 if(a!=0) { 143 tree[a].son[1]=b; 144 } 145 else {root=b;} 146 tree[b].size=n-i+1; 147 a=b; 148 } 149 150 } 151 void solve() { 152 init(); 153 char ord[15]; 154 int s,t; 155 siji(i,1,m) { 156 scanf("%s",ord); 157 if(ord[0]==‘T‘ || ord[0]==‘B‘ ) { 158 t=ord[0]==‘T‘ ? 0 : 1; 159 scanf("%d",&s); 160 in_hurry(s,t); 161 } 162 else if(ord[0]==‘I‘) { 163 scanf("%d%d",&s,&t); 164 insert(s,t); 165 } 166 else if(ord[0]==‘A‘){ 167 scanf("%d",&s); 168 printf("%d\n",ask(s)); 169 } 170 else if(ord[0]==‘Q‘) { 171 scanf("%d",&s); 172 query(root,s); 173 printf("%d\n",root); 174 } 175 } 176 } 177 int main(int argc, char const *argv[]) 178 { 179 #ifdef ivorysi 180 freopen("f1.in","r",stdin); 181 #endif 182 solve(); 183 }
以上是关于P2596 [ZJOI2006]书架的主要内容,如果未能解决你的问题,请参考以下文章