【输入格式 Input Format】 | |||
第一行为正整数n(n<=32767) ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个正整数a(<=1000000) ,表示第i天公司的营业额。 | |||
【输出格式 Output Format】 | |||
输出文件仅有一个正整数,即Sigma(每天最小的波动值) 。结果小于2^31 。 | |||
【样例输入 Sample Input】 | |||
6 5 1 2 5 4 6 |
|||
【样例输出 Sample Output】
12
时间限制 Time Limitation | |||
各个测试点1s |
结果说明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12
方法1:也可以先将所有数据输入进来,然后将其下标按照数据的大小排序O(nlog2n),然后对每一个数,向两边搜索第一个下标小于自己的数,并计算差值,即他与前驱和后继的差值(绝对值)去较小的。显然TLE。。。那就用强大的splay吧!
伸展树其实就是一种二叉排序树,只是它并不追求树的平衡,而是在每一次插入元素的时候,都通过左旋或右旋使之调整到树根,这样如果下次再访问这个元素的时候,访问操作就是O(1)了。如果我们要将当前节点移动到根,而不改变二叉排序树的特性。这样我们用这种数据结构后,算法就变成:将数据插入伸展树中并将数据调整到根,从根去找左子树的最右节点数据和右子树的最左节点数据,进行差的绝对值比较取小,并将所有的差的绝对值累加即可。splay,用到了查找树内某结点的前驱,后继和插入操作。
与上篇一样风格的代码:
#include <cstdio> #define keyTree (ch[ ch[root][1] ][0]) #define inf 0x3f3f3f3f const int maxn = 222222; int ans; struct SplayTree{ int ch[maxn][2]; int pre[maxn]; int root , top1; /*这是题目特定变量*/ int num[maxn]; int val[maxn]; inline void Rotate(int x,int f) { int y = pre[x]; ch[y][!f] = ch[x][f]; pre[ ch[x][f] ] = y; pre[x] = pre[y]; if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] = x; ch[x][f] = y; pre[y] = x; } inline void splay(int x,int goal) { while(pre[x] != goal) { if(pre[pre[x]] == goal) { Rotate(x , ch[pre[x]][0] == x); } else { int y = pre[x] , z = pre[y]; int f = (ch[z][0] == y); if(ch[y][f] == x) { Rotate(x , !f) , Rotate(x , f); } else { Rotate(y , f) , Rotate(x , f); } } } if(goal == 0) root = x; } //以下是题目的特定函数: inline void NewNode(int &x,int fa,int c) { x = ++top1; ch[x][0] = ch[x][1]= 0; pre[x]=fa; val[x] = c;/*这是题目特定函数*/ } /*初始化*/ inline int pre1(int x) { int tmp=ch[x][0]; if(tmp==0) return inf; while(ch[tmp][1]) { tmp=ch[tmp][1]; } return val[x]-val[tmp]; } inline int suc(int x) { int tmp=ch[x][1]; if(tmp==0) return inf; while(ch[tmp][0]) tmp=ch[tmp][0]; return val[tmp]-val[x]; } inline int ins(int data) { int x=root; while(ch[x][val[x]<data]) { if(val[x]==data) { splay(x,0); return 0; } x=ch[x][val[x]<data]; } NewNode(ch[x][val[x]<data],x,data); splay(ch[x][val[x]<data],0); return 1; } inline void init(int n) {/*这是题目特定函数*/ int tmp; ch[0][0] = ch[0][1] = pre[0] =0; root = top1 = 0;ans=0;int a,b; //为了方便处理边界,加两个边界顶点 for (int i = 0 ; i < n ; i ++) { scanf("%d",&tmp); if(i==0) { NewNode(root,0,tmp); ans+=tmp;continue; } if(ins(tmp)==0) continue; a=pre1(root); b=suc(root); ans+=a>b?b:a; } } }spt; int main() { int n , m; while(scanf("%d",&n)!=EOF) { spt.init(n); printf("%d\n",ans); } return 0; }