treap树---营业额统计
描述
Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:
该天的最小波动值 = min{ |该天以前某天的营业额 - 该天的营业额 | }
当最小波动值越大时,就说明营业情况越不稳定。而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。第一天的最小波动值为第一天的营业额。
输入
测试数据多组,每组的第一行为正整数n(1 <= n <= 32767), 表示该公司从成立一直到现在的天数. 接下来的n行每行有一个整数Ai(Ai <= 1000000) , 表示第i天的营业额。处理到EOF为止。
输出
每组数据占一行,每行输出一个整数,每天最小波动值的和。结果小于2^31
样例输入
样例输出
提示
5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12
题意 :求当前数与前面某个数差的绝对值的最小和;
思路:可使用treap树算法,利用treap树可以方便快速求得当前数之前出现的数的前继后驱,前继和后驱与当前数的差的绝对值小者即为所求,可用sum加上。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> using namespace std; struct data { int l,r,v,rnd; } tr[100005]; int size,root,ans1,ans2,f; void rturn(int &k) { int t=tr[k].l; tr[k].l=tr[t].r; tr[t].r=k; k=t; } void lturn(int &k) { int t=tr[k].r; tr[k].r=tr[t].l; tr[t].l=k; k=t; } void insert(int &k,int x) { if(k==0) { size++; k=size; tr[k].v=x; tr[k].rnd=rand(); return; } if(tr[k].v==x) f=1; else if(x>tr[k].v) { insert(tr[k].r,x); if(tr[tr[k].r].rnd<tr[k].rnd) lturn(k); } else { insert(tr[k].l,x); if(tr[tr[k].l].rnd<tr[k].rnd) rturn(k); } } void query_pro(int k,int x) { if(k==0) return; if(tr[k].v<x) { ans1=tr[k].v; query_pro(tr[k].r,x); } else query_pro(tr[k].l,x); } void query_sub(int k,int x) { if(k==0) return; if(tr[k].v>x) { ans2=tr[k].v; query_sub(tr[k].l,x); } else query_sub(tr[k].r,x); } int main() { int n; int x; while(scanf("%d",&n)!=EOF) { root=0; size=0; for(int i=0;i<100005;i++) { tr[i].l=0; tr[i].r=0; tr[i].v=0; } scanf("%d",&x); insert(root,x); int sum=x; for(int i=1;i<n;i++) { f=0; ans1=0-9999999; ans2=9999999; if(scanf("%d",&x)==EOF) x=0; insert(root,x); if(f) continue; query_pro(root,x); query_sub(root,x); sum+=min(x-ans1,ans2-x); } printf("%d\n",sum); } return 0; }
方法二:(Splay树)
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #define N 100005 #define inf 1<<29 using namespace std; int pre[N],key[N],ch[N][2],root,tot; int n; void NewNode(int &r,int father,int k) { r=++tot; pre[r]=father; key[r]=k; ch[r][0]=ch[r][1]=0; } void Rotate(int x,int kind) { int y=pre[x]; ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if(pre[y]) { ch[pre[y]][ch[pre[y]][1]==y]=x; } pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; } void Splay(int r,int goal) { while(pre[r]!=goal) { if(pre[pre[r]]==goal) Rotate(r,ch[pre[r]][0]==r); else { int y=pre[r]; int kind=ch[pre[y]][0]==y; if(ch[y][kind]==r) { Rotate(r,!kind); Rotate(r,kind); } else { Rotate(y,kind); Rotate(r,kind); } } } if(goal==0) root=r; } int Insert(int k) { int r=root; while(ch[r][key[r]<k]) { if(key[r]==k) { Splay(r,0); return 0; } r=ch[r][k>key[r]]; } NewNode(ch[r][k>key[r]],r,k); Splay(ch[r][k>key[r]],0); return 1; } int get_pre(int x) { int tmp=ch[x][0]; if(tmp==0) return inf; while(ch[tmp][1]) tmp=ch[tmp][1]; return key[x]-key[tmp]; } int get_next(int x) { int tmp=ch[x][1]; if(tmp==0) return inf; while(ch[tmp][0]) tmp=ch[tmp][0]; return key[tmp]-key[x]; } int main() { while(scanf("%d",&n)!=EOF) { root=tot=0; int ans=0; for(int i=1;i<=n;i++) { int num; if(scanf("%d",&num)==EOF) num=0; if(i==1) { ans+=num; NewNode(root,0,num); continue; } if(Insert(num)==0) continue; int a=get_pre(root); int b=get_next(root); ans+=min(a,b); } printf("%d\n",ans); } return 0; }