赤裸裸的splay平衡树

HYSBZ1588 http://www.lydsy.com/JudgeOnline/problem.php?id=1588

给我们n天的营业额, 要求出每天的最小波动值,然后加起来。  当天最小波动值 = 当天营业额 - (之前某天与当天营业额最接近的营业额)

所以维护一个spaly,将当天的营业额x插入splay中,然后将x旋转到根结点,然后找到左子树的最大值,右子树的最小值, 判断哪一个与当天的营业额差值小。

这里只用到了两种旋转,左旋和右旋。 没有考虑x的服 父亲是不是根节点。 也没有考虑共线不共线的问题。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<string.h>
  4 #include<algorithm>
  5 #include <vector>
  6 #include <math.h>
  7 using namespace std;
  8 const int INF = 0x7FFFFFFF;
  9 const int N = 100000 + 10;
 10 
 11 /*
 12 
 13             int y = pre[x];
 14         pre[next[x][kind]] = y;
 15         next[y][!kind] = next[x][kind];
 16         if(pre[y])
 17             next[pre[y]][next[pre[y]][1]==y] = x;
 18 
 19         //x旋转到了y的位置,所以y的父亲变成了x的父亲
 20         pre[x]  = pre[y];
 21         //
 22         next[x][kind] =  y;
 23         //x变成了y的父亲
 24         pre[y] = x;
 25 */
 26 struct SplayTree{
 27     int size,root;
 28     int next[N][2],pre[N],key[N];
 29     void init()
 30     {
 31         size = root = 0;
 32     }
 33     void newNode(int &rt, int father,int val)
 34     {
 35         rt = ++size;
 36         next[rt][0] = next[rt][1] = 0;
 37         pre[rt] = father;
 38         key[rt] = val;
 39     }
 40     //kind = 0表示左转, 为1表示右转
 41     void rotate(int x, int kind)
 42     {
 43         int y = pre[x];//x的父亲
 44         pre[x] = pre[y];
 45         pre[y] = x;
 46         next[y][!kind] = next[x][kind];
 47         pre[next[y][!kind]] = y;
 48         next[x][kind] = y;
 49         if(pre[x])
 50             next[pre[x]][next[pre[x]][1]==y] = x;
 51     }
 52     //将x旋转为goal的儿子
 53     void splay(int x, int goal)
 54     {
 55         while(pre[x]!=goal)
 56         {
 57             if(next[pre[x]][0] == x)//如果自己的父亲的左孩子
 58                 rotate(x,1);//右转
 59             else//左转
 60                 rotate(x,0);
 61         }
 62         //如果x旋转到了根结点,那么root的指向需要发生变化
 63         if(!goal)
 64             root = x;
 65     }
 66     bool insert(int k)
 67     {
 68         int x,y;
 69         for(x=root;next[x][k>key[x]];x=next[x][k>key[x]])
 70             if(k==key[x])//如有已经有了要插入的结点,那么返回false
 71             {
 72                 splay(x,0);
 73                 return false;
 74             }
 75         newNode(next[x][k>key[x]],x,k);
 76         splay(next[x][k>key[x]],0);
 77         return true;
 78     }
 79     int getPre()//如果有左子树,获得左子树最大值
 80     {
 81         int x = next[root][0];
 82         if(x)
 83         {
 84             while(next[x][1])
 85             {
 86                 x = next[x][1];
 87             }
 88             return key[x];
 89         }
 90         return INF;
 91     }
 92     int getNext()//如果有右子树,获得右子树最小值
 93     {
 94         int x = next[root][1];
 95         if(x)
 96         {
 97             while(next[x][0])
 98             {
 99                 x = next[x][0];
100             }
101             return key[x];
102         }
103         return INF;
104     }
105 };
106 SplayTree tree;
107 int main()
108 {
109     //将每一天的最小波动值加起来
110     int n,ans,x,a,b;
111     while(scanf("%d%d",&n,&ans)!=EOF)
112     {
113         tree.init();
114         tree.newNode(tree.root,0,ans);
115         while(--n)
116         {
117             x = 0;
118             scanf("%d",&x);
119 
120             //返回true,如果没有两个相同的结点,如果有,那么最小波动是0,不用加
121             if(tree.insert(x))
122             {
123                 a = tree.getPre();
124                 if(a<INF)
125                     a = x - a;
126                 b = tree.getNext();
127                 if(b<INF)
128                     b  -= x;
129 
130                 ans += min(a,b);
131             }
132         }
133         printf("%d
",ans);
134 
135     }
136     return 0;
137 }
原文地址:https://www.cnblogs.com/justPassBy/p/4894428.html