洛谷 P2234 [HNOI2002]营业额统计
题目描述
Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。
Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:
当最小波动值越大时,就说明营业情况越不稳定。
而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。
第一天的最小波动值为第一天的营业额。
输入输出格式
输入格式:
输入由文件’turnover.in’读入。
第一行为正整数n(n<=32767) ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数ai(|ai|<=1000000) ,表示第i天公司的营业额,可能存在负数。
输出格式:
输入输出样例
输入样例#1:
6 5 1 2 5 4 6
输出样例#1:
12
说明
结果说明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12
1.离散化+线段树
#include <algorithm> #include <ctype.h> #include <cstdio> #define N 40005 typedef long long LL; using namespace std; void read(int &x) { x=0;bool f=0; register char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=1; for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0'; x=f?(~x)+1:x; } struct node { int pos,dis; bool operator<(node a)const { return dis<a.dis; } }data[N]; int ans,a[N],n,value[N]; int min(int a,int b) {return a>b?b:a;} int max(int a,int b) {return a>b?a:b;} class type { private: struct TypeTree { int sum,l,r,Min,Max; }tr[N<<2|1]; public: void pushup(int k) { tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum; tr[k].Max=max(tr[k<<1].Max,tr[k<<1|1].Max); tr[k].Min=min(tr[k<<1|1].Min,tr[k<<1].Min); } void build(int k,int l,int r) { tr[k].l=l;tr[k].r=r; tr[k].Max=-1; tr[k].Min=0x7fffffff-1; if(l==r) return; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void update(int k,int t) { if(tr[k].l==tr[k].r) { tr[k].sum=1; tr[k].Max=tr[k].l; tr[k].Min=tr[k].r; return; } int mid=(tr[k].l+tr[k].r)>>1; if(t<=mid) update(k<<1,t); else update(k<<1|1,t); pushup(k); } int Query_Max(int k,int l,int r) { if(r<l) return -1; if(tr[k].sum==0) return -1; if(l<=tr[k].l&&tr[k].r<=r) return tr[k].Max; int mid=(tr[k].l+tr[k].r)>>1,ret=-2; if(l<=mid) ret=max(ret,Query_Max(k<<1,l,r)); if(r>mid) ret=max(ret,Query_Max(k<<1|1,l,r)); return ret; } int Query_Min(int k,int l,int r) { if(r<l) return 0x7fffffff-1; if(tr[k].sum==0) return 0x7fffffff-1; if(l<=tr[k].l&&tr[k].r<=r) return tr[k].Min; int mid=(tr[k].l+tr[k].r)>>1,ret=0x7fffffff; if(l<=mid) ret=min(ret,Query_Min(k<<1,l,r)); if(r>mid) ret=min(ret,Query_Min(k<<1|1,l,r)); return ret; } }; class type Tree; int main() { // freopen("turnover.in","r",stdin); // freopen("turnover.out","w",stdout); read(n); for(int i=1;i<=n;i++) { if(scanf("%d",&a[i])==EOF) a[i]=0; data[i].pos=i; data[i].dis=a[i]; } sort(data+1,data+1+n); int Size=1; a[data[1].pos]=Size; value[1]=data[1].dis; for(int i=2;i<=n;i++) { if(data[i].dis!=data[i-1].dis) Size++; a[data[i].pos]=Size; value[Size]=data[i].dis; } Tree.build(1,1,Size); ans=value[a[1]]; Tree.update(1,a[1]); for(int i=2;i<=n;i++) { int x=Tree.Query_Max(1,1,a[i]-1),y=Tree.Query_Min(1,a[i],n),inf=0x7fffffff; if(x!=-1) inf=min(inf,value[a[i]]-value[x]); if(y!=0x7fffffff-1) inf=min(inf,value[y]-value[a[i]]); ans+=inf; Tree.update(1,a[i]); } printf("%d",ans); return 0; }
2.裸splay 每插入一点 找前驱和后继
#include <ctype.h> #include <cstdio> #define N 50000 void read(int &x) { x=0;bool f=0;register char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=1; for(; isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0'; x=f?(~x)+1:x; } long long ans; int data[N],ch[N][2],fa[N],siz[N],cnt[N],root,n,cn; inline void pushup(int rt) { int l=ch[rt][0],r=ch[rt][1]; siz[rt]=siz[l]+siz[r]+cnt[rt]; } inline int son(int x) {return ch[fa[x]][1]==x;} inline void rotate(int x) { int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b]; if(z) ch[z][c]=x;else root=x;fa[x]=z; if(a) fa[a]=y;ch[y][b]=a; ch[x][!b]=y;fa[y]=x; pushup(y);pushup(x); } void splay(int x,int i) { while(fa[x]!=i) { int y=fa[x],z=fa[y]; if(z==i) rotate(x); else { if(son(x)==son(y)) { rotate(y); rotate(x); } else { rotate(x); rotate(x); } } } } void ins(int &rt,int x) { if(rt==0) { rt=++cn; data[cn]=x; siz[cn]=cnt[cn]=1; splay(cn,0); return; } if(data[rt]==x) { cnt[rt]++; siz[rt]++; splay(rt,0); return; } if(x<data[rt]) { ins(ch[rt][0],x); fa[ch[rt][0]]=rt; pushup(rt); } else { ins(ch[rt][1],x); fa[ch[rt][1]]=rt; pushup(rt); } } int getpre(int rt,int x) { int p=rt,ret=-1; while(p) { if(x<data[p]) p=ch[p][0]; else { ret=p; p=ch[p][1]; } } return ret; } int getsuc(int rt,int x) { int p=rt,ret=-1; while(p) { if(x>data[p]) p=ch[p][1]; else { ret=p; p=ch[p][0]; } } return ret; } int min(int a,int b) {return a>b?b:a;} int main() { read(n); for(int a,i=1;i<=n;i++) { read(a); if(i==1) ans+=a; else { int v1=getpre(root,a),v2=getsuc(root,a); if(v1==-1) ans+=(long long)(data[v2]-a),splay(v2,0); else if(v2==-1) ans+=(long long)(a-data[v1]),splay(v1,0); else ans+=(long long)min(a-data[v1],data[v2]-a),splay(v1,0),splay(v2,0); } ins(root,a); } printf("%lld\n",ans); return 0; }
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。