zoukankan      html  css  js  c++  java
  • UVA_11922 Permutation Transformer 【splay树】

    一、题目

    UVA11922

    二、分析

    为什么会有伸展树?

    伸展树与AVL的区别除了保持平衡的方式不同外,最重要的是在每次查找点时,让该点旋转到根结点,这里可以结合计算机里的局部性原理思考。

    伸展树有什么优势?

    有了伸展树,我们可以根据每次到根节点的值,根据二叉搜索树的性质,可以将整棵树划分成两个部分,左子树的值都比根结点值大,右子树的值都比根结点小。

    该题除了伸展树还用到了什么?

    该题还需要旋转,所以,需要像线段树的lazy标记一样标记是否需要旋转。

    有什么需要注意的地方?

    一定注意写法的不同,构建树的范围不同,如果没有定于null数组,则需要将建树范围从$[1,n]$扩为$[0,n]$,因为空指针的sum(表示以该结点为根的树的大小)是不清楚的。

    三、AC代码

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 
      5 using namespace std;
      6 
      7 struct Node
      8 {
      9     Node *ch[2];
     10     int sum, val;
     11     int flip;
     12     Node(int v = 0)
     13     {
     14         val = v;
     15         sum = 1; 
     16         flip = 0; 
     17         ch[0] = ch[1] = NULL;
     18     }
     19     int cmp(int x)
     20     {
     21         int d = x - (ch[0] == NULL ? 0 : ch[0]->sum);
     22         if(d == 1)  return -1;
     23         else    return d <= 0 ? 0 : 1;
     24     }
     25     void maintain()
     26     {
     27         sum = 1;
     28         if(ch[0] != NULL)   sum += ch[0]->sum;
     29         if(ch[1] != NULL)   sum += ch[1]->sum;
     30     }
     31     void pushdown()
     32     {
     33         if(flip) 
     34         {
     35             flip = 0;
     36             swap(ch[0], ch[1]);     //**
     37             if(ch[0] != NULL)
     38                 ch[0]->flip = !ch[0]->flip;
     39             if(ch[1] != NULL)
     40                 ch[1]->flip = !ch[1]->flip;
     41         }
     42     }
     43 };
     44 
     45 void build(Node* &o, int l, int r)
     46 {
     47     if(l > r)
     48         return;
     49     int mid = (l + r) >> 1;
     50     o = new Node(mid);
     51     build(o->ch[0], l, mid - 1);
     52     build(o->ch[1], mid + 1, r);
     53     o->maintain();
     54 }
     55 
     56 void rotate(Node* &o, int d)
     57 {
     58     Node *k = o->ch[d^1];
     59     o->ch[d^1] = k->ch[d];
     60     k->ch[d] = o;
     61     o->maintain();
     62     k->maintain();
     63     o = k;
     64 }
     65 
     66 
     67 void splay(Node* &o, int k)
     68 {
     69     o->pushdown();
     70     int d = o->cmp(k);
     71     if(d == 1)
     72         k -= (o->ch[0] == NULL ? 0 : o->ch[0]->sum) + 1;
     73     //当前结点不是第k个,则需要往上伸展
     74     if(d != -1)
     75     {
     76         Node *p = o->ch[d];
     77         p->pushdown();
     78 
     79         int d2 = p->cmp(k);
     80         int k2 = (d2 == 0 ? k : k - (p->ch[0] == NULL ? 0 :p->ch[0]->sum)  - 1);
     81         if(d2 != -1)
     82         {
     83             splay(p->ch[d2], k2);
     84             //x,x的父节点,x祖父结点三点共线
     85             if(d == d2) rotate(o, d^1);
     86             //不共线
     87             else    rotate(o->ch[d], d);
     88         }
     89         rotate(o, d^1);
     90     }
     91 }
     92 
     93 
     94 void print(Node* &o)    //一定要传引用
     95 {
     96     o->pushdown();
     97     if(o->ch[0] != NULL)    print(o->ch[0]);
     98     if(o->val)
     99         printf("%d
    ", o->val);
    100     if(o->ch[1] != NULL)    print(o->ch[1]);
    101 
    102     delete o;
    103     o = NULL;
    104 }
    105 
    106 Node* merge(Node* left, Node* right)
    107 {
    108     //left不能为NULL
    109     //因为初始化了sum为1,对于空指针的sum,不清楚大小
    110     //如何避免:建树从0开始,即保证sum>0
    111     splay(left, left->sum);
    112     left->ch[1] = right;
    113     left->maintain();
    114     return left;
    115 }
    116 
    117 
    118 void split(Node *o,  int k, Node* &left, Node* &right)
    119 {
    120     splay(o, k);
    121     left = o;
    122     right = o->ch[1];
    123     o->ch[1] = NULL;
    124     left->maintain();
    125 }
    126 
    127 
    128 int main()
    129 {
    130     //freopen("input.txt", "r", stdin);
    131     //freopen("out.txt", "w", stdout);
    132     int N, M, a, b;
    133     while(scanf("%d %d", &N, &M)==2)
    134     {
    135         Node *root = NULL;
    136         Node *left, *mid, *right, *o;
    137         //上述模板注意不能用空指针
    138         //必须从0开始,不然会RE
    139         build(root, 0, N);
    140 
    141         for(int i = 0; i < M; i++)
    142         {
    143             scanf("%d %d", &a, &b);
    144             //树里面有0所以是a
    145             split(root, a, left, o);
    146             split(o, b - a + 1, mid, right);
    147             mid->flip ^= 1;
    148             root = merge(merge(left, right), mid);
    149         }
    150         print(root);
    151     }
    152     return 0;
    153 }
  • 相关阅读:
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    449. Serialize and Deserialize BST
    114. Flatten Binary Tree to Linked List
    199. Binary Tree Right Side View
    173. Binary Search Tree Iterator
    98. Validate Binary Search Tree
    965. Univalued Binary Tree
    589. N-ary Tree Preorder Traversal
    eclipse设置总结
  • 原文地址:https://www.cnblogs.com/dybala21/p/10725777.html
Copyright © 2011-2022 走看看