Processing math: 100%

【题解】 [ZJOI2006]书架 (Splay)

懒得复制,戳我戳我

Solution:

  • 还是一个Splay,我们只用多存一个值rad来维护二叉树,然后用数组存下每个书对应的值是多少
  • Top操作,我是把s旋转到根节点,然后删除,将s对应的rad值调至最小,然后插入就可以
  • Bottom操作,就是和Top相反,删除后把rad调整至最大,然后插入
  • Insert操作,s==0不用操作,1时,就只用把s旋转到根节点,把左子树最大值旋转至左子树根节点,然后交换两个节点信息,并且交换数组储存的每个书对应的rad1就是相反的旋转右子树最小值就可以
  • Ask操作,就只用把s旋转到根节点,输出左子树大小
  • Query操作,就是找第s大的rad值对应的书籍编号就可以了
  • 一开始想怎么找编号好久,发现编号是1n就好操作了

Code:

//It is coded by Ning_Mew on 4.12
#include<bits/stdc++.h>
#define ls(x) node[x].ch[0]
#define rs(x) node[x].ch[1]
#define fa(x) node[x].fa
#define root node[0].ch[1]
using namespace std;

const int maxn=8e4+10,INF=1e9+7;

int n,m,tot,vall[maxn],low=0,up=0;
struct Node{
  int fa,ch[2],val,num,size;//num-> bian hao   val->rand()
}node[maxn];

void update(int x){node[x].size=node[ls(x)].size+node[rs(x)].size+1;}
void connect(int x,int fa,int how){node[x].fa=fa;node[fa].ch[how]=x;}
int ident(int x){return x==node[fa(x)].ch[0]?0:1;}
void rorate(int x){
  int Y=fa(x),R=fa(Y);int Yson=ident(x),Rson=ident(Y);
  connect(node[x].ch[Yson^1],Y,Yson);
  connect(Y,x,Yson^1);
  connect(x,R,Rson);
  update(Y);update(x);
}
void Splay(int x,int goal){
  int to=fa(goal);
  while(fa(x)!=to){
    if(fa(fa(x))==to)rorate(x);
    else if(ident(x)==ident(fa(x)))rorate(fa(x)),rorate(x);
    else rorate(x),rorate(x);
  }
}
int newnode(int x,int rad,int fa){node[++tot].val=rad;node[tot].num=x;node[tot].size=1;node[tot].fa=fa;return tot;}
void ins(int x,int rad){
  //cout<<x<<' '<<rad<<endl;
  int now=root;
  if(!root){newnode(x,rad,0);root=tot;return;}
  else{
    while(1){
      node[now].size++;
      int nxt=rad<node[now].val?0:1;
      if(!node[now].ch[nxt]){
	int p=newnode(x,rad,now);
	node[now].ch[nxt]=p;Splay(p,root);return;
      }
      now=node[now].ch[nxt];
    }
  }return;
}
int find(int x,int rad){
  int now=root;
  while(1){
    if(!now)return 0;
    if(node[now].val==rad){Splay(now,root);return now;}
    int nxt=rad<node[now].val?0:1;
    now=node[now].ch[nxt];
  }
}
void del(int x,int rad,int opt,int sum){//1->del 2->swap
  int pos=find(x,rad);
  if(!pos)return;
  if(opt==1){
    if(!ls(pos)&&!rs(pos)){root=0;return;}
    if(!ls(pos)){root=rs(pos);fa(root)=0;return;}
    else{
      int left=ls(pos);
      while(rs(left))left=rs(left);
      Splay(left,ls(pos));
      connect(rs(pos),left,1);
      connect(left,0,1);update(left);
    }
  }else{
    if(sum==0)return;
    if(sum==-1&&!ls(pos))return;
    if(sum==1&&!rs(pos))return;
    if(sum==-1){
      int left=ls(pos);
      while(rs(left))left=rs(left);
      Splay(left,ls(pos));
      swap(vall[ node[pos].num ],vall[ node[left].num ]);
      swap(node[pos].num,node[left].num);
    }else{
      int right=rs(pos);
      while(ls(right))right=ls(right);
      Splay(right,rs(pos));
      swap(vall[ node[pos].num ],vall[ node[right].num ]);
      swap(node[pos].num,node[right].num);
    }
  }
}
int rak(int x,int rad){int pos=find(x,rad);return node[ls(pos)].size;}
int kth(int x,int rad){
  int now=root;
  while(1){
    if(x-node[ls(now)].size==1){
      Splay(now,root);return node[now].num;}
    int nxt=x<=node[ls(now)].size?0:1;
    if(nxt){x=x-(node[ls(now)].size+1);}
    now=node[now].ch[nxt];
  }
}
string s;
int main(){
  scanf("%d%d",&n,&m);
  int x,t;
  for(int i=1;i<=n;i++){
    scanf("%d",&x);
    ins(x,++up);vall[x]=up;
  }
  //cout<<"ins finished"<<endl;
  for(int i=1;i<=m;i++){
    cin>>s;scanf("%d",&x);
    if(s=="Top"){
      del(x,vall[x],1,0);vall[x]=--low;
      ins(x,vall[x]);
    }
    if(s=="Bottom"){
      del(x,vall[x],1,0);vall[x]=++up;
      ins(x,vall[x]);
    }
    if(s=="Insert"){
      scanf("%d",&t); del(x,vall[x],2,t);
    }
    if(s=="Ask"){printf("%d\n",rak(x,vall[x]));}
    if(s=="Query"){printf("%d\n",kth(x,vall[x]));}
  }
  return 0;
}

posted @   Ning_Mew  阅读(183)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 上周热点回顾(1.20-1.26)
· 【译】.NET 升级助手现在支持升级到集中式包管理
点击右上角即可分享
微信分享提示