赤裸裸的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\n",ans); 134 135 } 136 return 0; 137 }