一.Treap树
左旋和右旋
右旋:
旋转代码,son[0]是左儿子,son[1]是右儿子
void rotate(Node * &o,int d){ //d=0,左旋转;d=1,右旋转
Node *k=o->son[d^1]; //d^1与1-d等价
o->son[d^1]=k->son[d]; //相当于途中的between E and S
k->son[d]=o;
o=k; //返回新的根
} Treap树的删除
如果待删除的结点是叶子结点,直接删除就好了。
如果待删除的结点x有两个子结点,那么找到优先级最大的一个子结点,把x向相反的反向旋转,也就是把x向树的下层调整,直到x被旋转到叶子结点,然后直接删除。
题目的意思:是对一群人有一个等级和一个id,一开始有一个老大,老大的等级是最高的,然后后面每输入一个人,对他的等级进行排序,输出和他等级最接近的一个人的id,由于题目的n比较大,因此普通的排序不行。
hdu 4585
1.含解释代码:
#include<bits/stdc++.h>
using namespace std;
int id[5000000+5];
/*由随机函数产生每个结点的优先级,从而避免二叉树的形态退化成链表。
虽然不能保证每次生成的Treap树一定是平衡的,但是期望的插入,删除,插入的时间复杂度都是O(logn)的
kth和find与名次树有关,时间复杂度都是O(logn)
*/
struct node{
int size; //以这个结点为根的子树的结点总数量,用于名次树
int rank; //优先级
int key; //键值
node *son[2];
bool operator<(const node &a)const{return rank<a.rank;};
int cmp(int x) {
if(x==key) return -1;
return x<key?0:1;
}
inline void update() { //更新size
size=1;
if(son[0]) size+=son[0]->size;
if(son[1]) size+=son[1]->size;
}
};
void rotate(node* &o,int d) { //d为0时左旋,d为1时右旋
node *k=o->son[d^1]; //如果d为0,k为o的右儿子,d^1与1-d等价,但是更快
o->son[d^1]=k->son[d]; //o的右儿子为k的左儿子
k->son[d]=o; //k的左儿子为o
o->update();
k->update();
o=k;
}
void insert(node* &o,int x) {
if(o) { //如果这个位置有结点了继续下去
int d=o->cmp(x);
insert(o->son[d],x);
++o->size;
if(o<o->son[d])
rotate(o,d^1);
}
else { //这个位置没有结点,可以插入x
o=new node();
o->son[0]=o->son[1]=NULL;
o->rank=rand();
o->key=x;
o->size=1;
}
}
int kth(node *o,int k) {
if(k<=0||k>o->size) //t-1和t+1可能不存在
return -1;
int s=o->son[1]?o->son[1]->size:0;
if(k==s+1) return o->key;
if(k<=s) kth(o->son[1],k);
else kth(o->son[0],k-s-1);
}
int find(node *o,int k) {
int d=o->cmp(k); //d为k在这个结点上的位置
if(d==-1)
return o->son[1]?o->son[1]->size+1:1;
if(d) find(o->son[d],k);
else { //左子树要另外考虑
int tmp=find(o->son[0],k);
if(tmp==-1) return -1;
return o->son[1]?o->son[1]->size+tmp+1:tmp+1;
}
}
int main() {
int n;
while(~scanf("%d",&n)&&n) {
srand(time(NULL));
int k,g;
scanf("%d%d",&k,&g);
node *root=new node();
root->son[0]=root->son[1]=NULL;
root->rank=rand(); root->key=g; root->size=1;
id[g]=k;
printf("%d 1\n",k);
for(int i=2;i<=n;++i) {
scanf("%d%d",&k,&g);
id[g]=k;
insert(root,g);
int t=find(root,g);
int ans,ans1,ans2;
ans1=kth(root,t-1);
ans2=kth(root,t+1);
if(ans1!=-1&&ans2!=-1) ans= ans1-g>=g-ans2?ans2:ans1;
else if(ans2!=-1) ans=ans2;
else ans=ans1;
printf("%d %d\n",k,id[ans]);
}
}
}2.无解释代码:
#include<bits/stdc++.h>
using namespace std;
int id[5000000+5];
struct node{
int size;
int rank;
int key;
node *son[2];
bool operator<(const node &a)const{return rank<a.rank;};
int cmp(int x) {
if(x==key) return -1;
return x<key?0:1;
}
inline void update() {
size=1;
if(son[0]) size+=son[0]->size;
if(son[1]) size+=son[1]->size;
}
};
void rotate(node* &o,int d) {
node *k=o->son[d^1];
o->son[d^1]=k->son[d];
k->son[d]=o;
o->update();
k->update();
o=k;
}
void insert(node* &o,int x) {
if(o) {
int d=o->cmp(x);
insert(o->son[d],x);
++o->size;
if(o<o->son[d])
rotate(o,d^1);
}
else {
o=new node();
o->son[0]=o->son[1]=NULL;
o->rank=rand();
o->key=x;
o->size=1;
}
}
int kth(node *o,int k) {
if(k<=0||k>o->size)
return -1;
int s=o->son[1]?o->son[1]->size:0;
if(k==s+1) return o->key;
if(k<=s) kth(o->son[1],k);
else kth(o->son[0],k-s-1);
}
int find(node *o,int k) {
int d=o->cmp(k);
if(d==-1)
return o->son[1]?o->son[1]->size+1:1;
if(d) find(o->son[d],k);
else {
int tmp=find(o->son[0],k);
if(tmp==-1) return -1;
return o->son[1]?o->son[1]->size+tmp+1:tmp+1;
}
}
int main() {
int n;
while(~scanf("%d",&n)&&n) {
srand(time(NULL));
int k,g;
scanf("%d%d",&k,&g);
node *root=new node();
root->son[0]=root->son[1]=NULL;
root->rank=rand(); root->key=g; root->size=1;
id[g]=k;
printf("%d 1\n",k);
for(int i=2;i<=n;++i) {
scanf("%d%d",&k,&g);
id[g]=k;
insert(root,g);
int t=find(root,g);
int ans,ans1,ans2;
ans1=kth(root,t-1);
ans2=kth(root,t+1);
if(ans1!=-1&&ans2!=-1) ans= ans1-g>=g-ans2?ans2:ans1;
else if(ans2!=-1) ans=ans2;
else ans=ans1;
printf("%d %d\n",k,id[ans]);
}
}
}二.Splay树
hdu 1890
1.前言:
2.含解释代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int root; //根
int rev[maxn],pre[maxn],size[maxn];
//rev[i],标记i被翻转;pre[i],i的父结点;size[i],i的子树上结点的个数
int tree[maxn][2];//记录树:tree[i][0],i的左儿子;tree[i][1],i的右儿子
struct node{
int val,id;
bool operator<(const node &A)const { //用于sort排序
if(val==A.val) return id<A.id;
return val<A.val;
}
}nodes[maxn];
void pushup(int x) { //计算以x为根的子树包含多少子结点
size[x]=size[tree[x][0]]+size[tree[x][1]]+1;
}
void update_rev(int x) { //用标记的方式记录翻转情况,减少直接操作的次数,等Splay操作再处理
if(!x) return;
swap(tree[x][0],tree[x][1]); //先翻转x:交换左右儿子
rev[x]^=1; //标记x被翻转--它的儿子还没翻
}
/*结点是按照中序遍历创建的,所以左儿子是头,右儿子是尾,
机械臂翻转是调换头和尾,也就是左右儿子*/
void pushdown(int x) { //在做Splay时,根据本题的需要,处理机械臂翻转
if(rev[x]) {
update_rev(tree[x][0]);
update_rev(tree[x][1]);
rev[x]=0;
}
}
void Rotate(int x,int d) { //旋转,d=0为左旋,d=1为右旋
int y=pre[x];
pushdown(y);
pushdown(x);
tree[y][!d]=tree[x][d];
pre[tree[x][d]]=y;
if(pre[y])
tree[pre[y]][tree[pre[y]][1]==y]=x;
pre[x]=pre[y];
tree[x][d]=y;
pre[y]=x;
pushup(y);
}
void splay(int x,int goal) { //把结点x旋转为goal的儿子,如果goal是0,则旋转到根
pushdown(x); //是时候翻转x的儿子并且标记它的儿子了,防止x的儿子走了导致标记失效,以下都是
//一直选择,直到x成为goal的儿子
while(pre[x]!=goal) if(pre[pre[x]]==goal) {
pushdown(pre[x]); pushdown(x);
Rotate(x,tree[pre[x]][0]==x);
}//情况1:x的父结点是根,单旋一次即可
else {
pushdown(pre[pre[x]]); pushdown(pre[x]); pushdown(x);
int y=pre[x];
int d=(tree[pre[y]][0]==y);
if(tree[y][d]==x) {
Rotate(x,!d);
Rotate(x,d);
}//情况(2): x、x的父、x的父的父,不共线
else {
Rotate(y,d);
Rotate(x,d);
}//情况(3): x、x的父、x的父的父,共线
}//x的父结点不是根
pushup(x);
if(goal==0) root=x; //如果goal是0,则将根节点更新为x
}
int get_max(int x) { //和找以当前结点为根树中的最大值一样的操作,只是本题的BST树有序结构会被打乱
pushdown(x);
while(tree[x][1]) {
x=tree[x][1];
pushdown(x);
}
return x;
}
void del_root() { //删除根结点
if(tree[root][0]==0) { //因为机械手是翻转根节点的左子树,所以优先把左子树的结点移动根结点最好
root=tree[root][1];
pre[root]=0;
}
else { //先把新根结点移到根,再取代旧的根结点
int m=get_max(tree[root][0]);
splay(m,root);
tree[m][1]=tree[root][1];
pre[tree[root][1]]=m;
root=m;
pre[root]=0;
pushup(root);
}
}
void newnode(int &x,int fa,int val) {
x=val;
pre[x]=fa;
size[x]=1;
rev[x]=0;
tree[x][0]=tree[x][1]=0;
}
void buildtree(int &x,int l,int r,int fa) {
if(l>r) return;
int mid=(l+r)>>1;
newnode(x,fa,mid);
buildtree(tree[x][0],l,mid-1,x);
buildtree(tree[x][1],mid+1,r,x);
pushup(x);
}
int main() {
int n;
while(~scanf("%d",&n)&&n) {
buildtree(root,1,n,0); //把初始位置按中序遍历1...n的顺序建立二叉树
//结束后root=(n+1)/2,也就是树的根节点
for(int i=1;i<=n;++i) { //val只用来排序,id为树的结点
scanf("%d",&nodes[i].val); nodes[i].id=i;
}
sort(nodes+1,nodes+n+1);
for(int i=1;i<n;++i) { //依次取出值最小的结点---取名x
splay(nodes[i].id,0); //先将x提到根结点去
update_rev(tree[root][0]);//翻转结点x,对结点x做标记
printf("%d ",i+size[tree[root][0]]);//左边元素的个数就是它现在的位置
del_root(); //删除结点x,为了序列不变,先找到左子树最右的结点(可以理解为左子树最大的点)
} //注意,翻转会改变BST树的有序结构,所以最右边不一定是最大的点,找不到时取顶点
printf("%d\n",n);
}
return 0;
}3.无解释代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int root;
int rev[maxn],pre[maxn],size[maxn];
int tree[maxn][2];
struct node{
int val,id;
bool operator<(const node &A)const {
if(val==A.val) return id<A.id;
return val<A.val;
}
}nodes[maxn];
void pushup(int x) {
size[x]=size[tree[x][0]]+size[tree[x][1]]+1;
}
void update_rev(int x) {
if(!x) return;
swap(tree[x][0],tree[x][1]);
rev[x]^=1;
}
void pushdown(int x) {
if(rev[x]) {
update_rev(tree[x][0]);
update_rev(tree[x][1]);
rev[x]=0;
}
}
void Rotate(int x,int d) {
int y=pre[x];
pushdown(y);
pushdown(x);
tree[y][!d]=tree[x][d];
pre[tree[x][d]]=y;
if(pre[y])
tree[pre[y]][tree[pre[y]][1]==y]=x;
pre[x]=pre[y];
tree[x][d]=y;
pre[y]=x;
pushup(y);
}
void splay(int x,int goal) {
pushdown(x);
while(pre[x]!=goal) if(pre[pre[x]]==goal) {
pushdown(pre[x]); pushdown(x);
Rotate(x,tree[pre[x]][0]==x);
}
else {
pushdown(pre[pre[x]]); pushdown(pre[x]); pushdown(x);
int y=pre[x];
int d=(tree[pre[y]][0]==y);
if(tree[y][d]==x) {
Rotate(x,!d);
Rotate(x,d);
}
else {
Rotate(y,d);
Rotate(x,d);
}
}
pushup(x);
if(goal==0) root=x;
}
int get_max(int x) {
pushdown(x);
while(tree[x][1]) {
x=tree[x][1];
pushdown(x);
}
return x;
}
void del_root() {
if(tree[root][0]==0) {
root=tree[root][1];
pre[root]=0;
}
else {
int m=get_max(tree[root][0]);
splay(m,root);
tree[m][1]=tree[root][1];
pre[tree[root][1]]=m;
root=m;
pre[root]=0;
pushup(root);
}
}
void newnode(int &x,int fa,int val) {
x=val;
pre[x]=fa;
size[x]=1;
rev[x]=0;
tree[x][0]=tree[x][1]=0;
}
void buildtree(int &x,int l,int r,int fa) {
if(l>r) return;
int mid=(l+r)>>1;
newnode(x,fa,mid);
buildtree(tree[x][0],l,mid-1,x);
buildtree(tree[x][1],mid+1,r,x);
pushup(x);
}
int main() {
int n;
while(~scanf("%d",&n)&&n) {
buildtree(root,1,n,0);
for(int i=1;i<=n;++i) {
scanf("%d",&nodes[i].val); nodes[i].id=i;
}
sort(nodes+1,nodes+n+1);
for(int i=1;i<n;++i) {
splay(nodes[i].id,0);
update_rev(tree[root][0]);
printf("%d ",i+size[tree[root][0]]);
del_root();
}
printf("%d\n",n);
}
return 0;
}
京公网安备 11010502036488号