zoukankan      html  css  js  c++  java
  • [洛谷P3850][题解][TJOI2007]书架

    题目戳这里

    平衡树的题第一次一遍过,写篇博客庆祝一下,顺便加深一下印象

    这道题要求我们支持任意插入

    可以用Splay做,具体做法如下:

    设要插入到第k个节点后,

    则先将k旋至根,再将k-1旋至k的左儿子,

    可以发现,此时k-1的右儿子是空的,我们将新节点插在这里就可以满足题意

    Code:

      1 #include<bits/stdc++.h>
      2 #define INF 0x3f3f3f3f
      3 #define ls ch[k][0]
      4 #define rs ch[k][1]
      5 #define N 1000010
      6 using namespace std;
      7 inline void Read(int &x){
      8     int f=1;
      9     char c=getchar();
     10     x=0;
     11     while(c<'0'||c>'9'){
     12         if(c=='-')f=-1;
     13         c=getchar();
     14     }
     15     while(c>='0'&&c<='9'){
     16         x=(x<<3)+(x<<1)+c-'0';
     17         c=getchar();
     18     }
     19     x*=f;
     20 }
     21 
     22 /*变量名解释:
     23 n,m,q:如题意 
     24 tot:当前点数,root:当前根 
     25 ch[i][0/1]:i的左/右儿子,fa[i]:i的父亲 
     26 data[i]:i对应的编号,cnt[i]:i有几个,siz[i]:i的子树大小 
     27 bks[i]:第i个字符串(书名)*/ 
     28 int n,m,q,tot,root;
     29 int ch[N][2],fa[N],data[N],cnt[N],siz[N];
     30 string bks[N];
     31 
     32 inline int Son(int k){//k是他爹的哪个儿子 
     33     return ch[fa[k]][1]==k;
     34 }
     35 
     36 inline void Pushup(int k){//向上更新 
     37     siz[k]=siz[ls]+siz[rs]+cnt[k];
     38 }
     39 
     40 inline void Rotate(int k){//旋转 
     41     int fk=fa[k],gfk=fa[fk];
     42     int b=Son(k),c=Son(fk),a=ch[k][!b];
     43     ch[fk][b]=a,fa[a]=fk;//
     44     ch[gfk][c]=k,fa[k]=gfk;//
     45     ch[k][!b]=fk,fa[fk]=k;//
     46     Pushup(fk),Pushup(k);
     47 }
     48 
     49 inline void Splay(int k,int to){//将k伸展至to 
     50     while(fa[k]!=to){
     51         int fk=fa[k],gfk=fa[fk];
     52         if(gfk!=to){
     53             if(Son(k)==Son(fk))Rotate(fk);
     54             else Rotate(k);
     55         }
     56         Rotate(k);
     57     }
     58     if(!to)root=k;
     59 }
     60 
     61 inline void Find(int num){//把值为num的节点搞到根 
     62     if(!root)return;
     63     int k=root;
     64     while(data[ch[k][num>data[k]]]&&num!=data[k]){
     65         k=ch[k][num>data[k]];
     66     }
     67     Splay(k,0);
     68 }
     69 
     70 inline void Insert(int num){//插入值为num的节点 
     71     int k=root,tmp=0;
     72     while(k&&data[k]!=num){//
     73         tmp=k;
     74         k=ch[k][num>data[k]];
     75     }
     76     if(k)cnt[k]++;//有了,直接记录 
     77     else {//还没有,需要新增 
     78         k=++tot;
     79         if(tmp)ch[tmp][num>data[tmp]]=k;
     80         ls=rs=0;
     81         data[k]=num,fa[k]=tmp;
     82         cnt[k]=siz[k]=1;
     83     }
     84     Splay(k,0);
     85 }
     86 
     87 inline int GetRank(int num){//查询num的排名 
     88     Find(num);
     89     return siz[ch[root][0]]+1;
     90 }
     91 
     92 inline int GetKth(int num){//查询第num大 
     93     int k=root;
     94     while(114514){
     95         if(ls&&siz[ls]>=num)k=ls;
     96         else {
     97             if(siz[ls]+cnt[k]<num){
     98                 num-=(siz[ls]+cnt[k]);
     99                 k=rs;
    100             }else return k;
    101         }
    102     }
    103 }
    104 
    105 inline int GetPre(int num){//找前驱 
    106     Find(num);
    107     if(data[root]<num)return root;
    108     int k=ch[root][0];
    109     while(rs)k=rs;
    110     return k;
    111 }
    112 
    113 inline int GetSuc(int num){//找后继 
    114     Find(num);
    115     if(data[root]>num)return root;
    116     int k=ch[root][1];
    117     while(ls)k=ls;
    118     return k;
    119 }
    120 
    121 inline void Delete(int num){//删节点 
    122     int lst=GetPre(num),nxt=GetSuc(num);
    123     Splay(lst,0),Splay(nxt,lst);
    124     //找到前驱后缀,中间那个拎出来处决 
    125     int victim=ch[nxt][0];
    126     if(cnt[victim]>1){
    127         cnt[victim]--;
    128         Splay(victim,0);
    129     }else {
    130         ch[nxt][0]=0;
    131         Splay(nxt,0);
    132     }
    133 }
    134 
    135 int main(){
    136     Read(n);
    137     Insert(-INF),Insert(INF);//防止一些奇奇怪怪的毛病 
    138     for(int i=1;i<=n;i++){
    139         cin>>bks[i];
    140         Insert(i);
    141     }
    142     Read(m);
    143     for(int i=1;i<=m;i++){
    144         int k;
    145         cin>>bks[n+i];
    146         Read(k);
    147         k+=2;
    148         //k旋到根,k-1(k的前驱)旋到k左边
    149         //此时k-1右边无节点,插到这里即可 
    150         //找+旋 
    151         int kth=GetKth(k);
    152         Splay(kth,0);
    153         int sucth=GetKth(k-1);
    154         Splay(sucth,kth);
    155         //添加节点 
    156         ch[sucth][1]=++tot,fa[tot]=sucth;
    157         ch[tot][0]=ch[tot][1]=0;
    158         data[tot]=k,cnt[tot]=siz[tot]=1;
    159         Pushup(sucth),Pushup(kth);
    160     }
    161     Read(q);
    162     for(int i=1;i<=q;i++){
    163         int k;
    164         Read(k);
    165         int kth=GetKth(k+2);
    166         cout<<bks[kth-2]<<endl;
    167     }
    168     return 0;
    169 }//完璧な結末~ 
    内容来自_ajhfff_的博客(https://www.cnblogs.com/juruoajh/),未经允许,不得转载。
  • 相关阅读:
    配置利用Tilcon 5.8 Radar Demo for vxWorks 6.8
    安装源REMI做源 CentOS上 PHP 的安装和升级
    产品苹果乔布斯和盖茨眼中真实的对方
    平台微软将死的平台:.Net
    企业生活12大颠覆性技术:移动互联网居首
    设备代工富士康加入Firefox OS阵营,下周将发布搭载Firefox OS的设备
    线程对象Android 开发之多线程处理、Handler 详解
    输出hadoop[置顶] hadoop之测试KMeans(二):输出结果分析
    个位数字poj 3126 Prime Path
    nullnullGet previous business day
  • 原文地址:https://www.cnblogs.com/juruoajh/p/12304975.html
Copyright © 2011-2022 走看看