zoukankan      html  css  js  c++  java
  • ACM之路(20)—— Splay初探

      由于数据结构上老师讲了AVL树的rotate,然后去学了一下treap和Splay,这些数据结构还真是神奇啊!

      treap暂时只知道名次树的作用(就是一段动态变化的有序数列,找第K大的元素,用set显然是O(n)的。。)。

      好,正式介绍SplayTree这个神奇的数据结构:暂时的理解是,用于解决一些线段树解决不了的区间问题,比方说区间翻转,区间删除并插入等等(似乎分块也可以解决一些xjbg的区间问题)。。然后,Splay还可以解决掉LCT的问题(暂时还不会,,下次继续学习)。

      然后就愉快地掏出模板吧(直接修改了铭神的模板)。。仓鼠挂的平衡树

      G题,区间翻转+区间切割的。直接掏出模板套上去就是了:

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <string.h>
      4 #define tochange (root->ch[1]->ch[0])
      5 using namespace std;
      6 const int N = 300000 + 100;
      7 struct node *nill, *root;
      8 struct node {
      9     int val;
     10     int sz;
     11     bool rev;
     12     node *ch[2],*fa;
     13     void init(int v = 0)
     14     {
     15         ch[0] = ch[1] = fa = nill;
     16         val = v;
     17         sz = 1;
     18     }
     19     void up() {
     20         if (this==nill) return ;
     21         sz = ch[0]->sz + ch[1]->sz + 1;
     22     }
     23     void down() {
     24         if (this==nill) return ;
     25         if(rev)
     26         {
     27             rev = false;
     28             ch[0]->rev ^= 1;
     29             ch[1]->rev ^= 1;
     30             swap(ch[0], ch[1]);
     31         }
     32     }
     33     bool d() {
     34         return fa->ch[1]==this;
     35     }
     36     void reverse() {
     37         rev ^= 1;
     38         std::swap(ch[0],ch[1]);
     39     }
     40     void setc(node *o,int c) {
     41         ch[c] = o;
     42         o->fa = this;
     43         up();
     44     }
     45     void rot() {
     46         int c = d(),cc = fa->d();
     47         node *z = fa->fa;
     48         node *tmp = fa;
     49         fa->setc(ch[c^1],c);
     50         setc(tmp,c^1);
     51         if(z!=nill) z->setc(this,cc);
     52         else fa = z;  // 这里的if-else不加也行,因为对于nill来说无论儿子是谁都无所谓,
     53                       // 并且,setc时的up对nill无效
     54     }
     55     void D() {
     56         if (this==nill) return ;
     57         fa->D();
     58         down();
     59     }
     60     void splay(node *aim = nill) {
     61         D();
     62         while (fa!=aim) {
     63             if (fa->fa!=aim) {
     64                 d()==fa->d() ? fa->rot() : rot();
     65             }
     66             rot();
     67         }
     68         if(aim == nill) root = this;
     69     }
     70 }memo[N], *bat;
     71 
     72 node* findK(node* o, int k)
     73 {
     74     while(1)
     75     {
     76         o->down();
     77         if(o->ch[0]->sz + 1 == k)
     78         {
     79             return o;
     80         }
     81         if(o->ch[0]->sz >= k) o = o->ch[0];
     82         else
     83         {
     84             k -= o->ch[0]->sz + 1;
     85             o = o->ch[1];
     86         }
     87     }
     88 }
     89 
     90 node* get_min(node* o)
     91 {
     92     /*while(o->ch[0] != nill)
     93     {
     94         o->down();
     95         o = o->ch[0];
     96     }
     97     return o;*/
     98     // 上面写法错了,为什么?
     99     // -因为可能o本来是没有左边的儿子的,一交换以后就有了,所以要先down().
    100     o->down();
    101     while(o->ch[0] != nill)
    102     {
    103         o = o->ch[0];
    104         o->down();
    105     }
    106     return o;
    107 }
    108 
    109 void Reverse(int a,int b)
    110 {
    111     node* x = findK(root,a);
    112     node* y = findK(root,b+2);
    113     x->splay();
    114     y->splay(root);
    115     tochange->rev ^= 1;
    116 }
    117 
    118 void Cut(int a,int b,int c)
    119 {
    120     node* x = findK(root, a);
    121     node* y = findK(root, b+2);
    122     x->splay();
    123     y->splay(root);
    124     node* temp = tochange;
    125     y->setc(nill, 0);
    126     node* z = findK(root, c+1);
    127     z->splay();
    128     z = get_min(root->ch[1]);
    129     z->splay(root);
    130     root->ch[1]->setc(temp, 0);
    131 }
    132 
    133 int n,m;
    134 node* newNode(int val = 0)
    135 {
    136     node* o = bat ++;
    137     o->init(val);
    138     return o;
    139 }
    140 void init()
    141 {
    142     bat = memo;
    143     nill = newNode(); nill->sz = 0;
    144     root = newNode(); root->fa = nill;
    145     node* p = newNode(), *p2 = nill;
    146     root->setc(p, 1);
    147     p = nill;
    148     for(int i=1;i<=n;i++)
    149     {
    150         p2 = newNode(i);
    151         p2->setc(p, 0);
    152         p = p2;
    153     }
    154     root->ch[1]->setc(p, 0);
    155 }
    156 
    157 int cnt = 0;
    158 void print(node* o)
    159 {
    160     if(o == nill) return ;
    161     o->down();
    162     print(o->ch[0]);
    163     if(cnt >= 1 && cnt <= n)
    164     {
    165         if(cnt > 1) printf(" ");
    166         printf("%d",o->val);
    167     }
    168     cnt++;
    169     print(o->ch[1]);
    170 }
    171 
    172 int main()
    173 {
    174     while(scanf("%d%d",&n,&m) == 2)
    175     {
    176         if(n == -1 && m == -1) break;
    177         init();
    178 
    179         char s[10];
    180         while(m--)
    181         {
    182             scanf("%s",s);
    183             if(s[0] == 'F')
    184             {
    185                 int a,b;scanf("%d%d",&a,&b);
    186                 Reverse(a,b);
    187             }
    188             else
    189             {
    190                 int a,b,c;
    191                 scanf("%d%d%d",&a,&b,&c);
    192                 Cut(a,b,c);
    193             }
    194         }
    195         cnt = 0;
    196         print(root);
    197         puts("");
    198     }
    199 }
    Splay区间翻转+区间切割

      然后A题,可以直接map写,然后弹出最大最小就可以了。为了练手Splay,特地用Splay写了一遍(惊喜的是时间比map的要短= =)。

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <string.h>
      4 #define tochange (root->ch[1]->ch[0])
      5 using namespace std;
      6 const int N = 300000 + 100;
      7 struct node *nill, *root;
      8 struct node {
      9     int val, key;
     10     int sz;
     11     bool rev;
     12     node *ch[2],*fa;
     13     void init(int v,int p)
     14     {
     15         ch[0] = ch[1] = fa = nill;
     16         val = v;
     17         key = p;
     18         sz = 1;
     19     }
     20     void up() {
     21         if (this==nill) return ;
     22         sz = ch[0]->sz + ch[1]->sz + 1;
     23     }
     24     void down() {
     25         if (this==nill) return ;
     26         if(rev)
     27         {
     28             rev = false;
     29             ch[0]->rev ^= 1;
     30             ch[1]->rev ^= 1;
     31             swap(ch[0], ch[1]);
     32         }
     33     }
     34     bool d() {
     35         return fa->ch[1]==this;
     36     }
     37     void reverse() {
     38         rev ^= 1;
     39         std::swap(ch[0],ch[1]);
     40     }
     41     void setc(node *o,int c) {
     42         ch[c] = o;
     43         o->fa = this;
     44         up();
     45     }
     46     void rot() {
     47         int c = d(),cc = fa->d();
     48         node *z = fa->fa;
     49         node *tmp = fa;
     50         fa->setc(ch[c^1],c);
     51         setc(tmp,c^1);
     52         if(z!=nill) z->setc(this,cc);
     53         else fa = z;
     54     }
     55     void D() {
     56         if (this==nill) return ;
     57         fa->D();
     58         down();
     59     }
     60     void splay(node *aim = nill) {
     61         D();
     62         while (fa!=aim) {
     63             if (fa->fa!=aim) {
     64                 d()==fa->d() ? fa->rot() : rot();
     65             }
     66             rot();
     67         }
     68         if(aim == nill) root = this;
     69     }
     70 }memo[N], *bat;
     71 
     72 node* newNode()
     73 {
     74     node* o = bat ++;
     75     return o;
     76 }
     77 void init()
     78 {
     79     bat = memo;
     80     nill = newNode(); nill->sz = 0;
     81     root = nill;
     82 }
     83 
     84 void _insert(node* o, node* p)
     85 {
     86     if(p->key < o->key)
     87     {
     88         if(o->ch[0] == nill) {o->setc(p, 0);return ;}
     89         else _insert(o->ch[0], p);
     90     }
     91     else if(p->key > o->key)
     92     {
     93         if(o->ch[1] == nill) {o->setc(p, 1);return ;}
     94         else _insert(o->ch[1], p);
     95     }
     96 }
     97 void insert(int val,int key)
     98 {
     99     node* p = newNode();
    100     p->init(val, key);
    101     if(root == nill) root = p;
    102     else _insert(root, p);
    103 }
    104 
    105 node* get_max_or_min(node* o, int op)
    106 {
    107     //o->down();
    108     while(o->ch[op] != nill)
    109     {
    110         o = o->ch[op];
    111         //o->down();
    112     }
    113     return o;
    114 }
    115 // 1->pop_max, 0->pop_min
    116 void pop_max_or_min(int op)
    117 {
    118     if(root == nill) {printf("0
    ");return;}
    119     node* p = get_max_or_min(root, op);
    120     p->splay(nill);
    121     printf("%d
    ",p->val);
    122     root = p->ch[op^1];
    123     root->fa = nill;
    124 }
    125 
    126 int main()
    127 {
    128     init();
    129     int n;
    130     while(scanf("%d",&n) == 1 && n)
    131     {
    132         if(n == 1)
    133         {
    134             int val, key;scanf("%d%d",&val,&key);
    135             insert(val,key);
    136         }
    137         else if(n == 2) pop_max_or_min(1);
    138         else pop_max_or_min(0);
    139     }
    140     return 0;
    141 }
    Splay维护最大或最小key的节点

      

      然后,,因为要复习了,暂时就放放了。。

  • 相关阅读:
    「 HDU P3336 」 Count the string
    Luogu P4016 「 网络流 24 题 」负载平衡问题
    『 学习笔记 』网络最大流
    Luogu P4014 「 网络流 24 题 」分配问题
    Loj #6000.「 网络流 24 题 」搭配飞行员
    牛客练习赛25 C 再编号
    线段树--从入门到入土
    网络流学习--费用流
    网络流--最大流
    五校联考解题报告
  • 原文地址:https://www.cnblogs.com/zzyDS/p/6200529.html
Copyright © 2011-2022 走看看