[ H N O I 2002 ] 营 业 额 统 计 [HNOI2002]营业额统计 [HNOI2002]营业额统计
Description:
- 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。 Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况: 该天的最小波动值 当最小波动值越大时,就说明营业情况越不稳定。 而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。 第一天的最小波动值为第一天的营业额。
Input Format
- 第一行为正整数 ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数(有可能有负数) ,表示第i
天公司的营业额。
天数n<=32767,
每天的营业额ai <= 1,000,000。
最后结果T<=2^31
Output Format
- 输出文件仅有一个正整数,即Sigma(每天最小的波动值) 。结果小于2^31 。
Sample Input
- 6
5
1
2
5
4
6
Sample Output
- 12
TJ:
网上清一色的都是平衡树、伸展树的题解,其实这道题用CDQ分治也能很快写出来(代码量骤减)。由于可以进行离线处理,并且所有点都只和它左边的点有关,很容易想到CDQ分治,关键的部分就是在分治之后归并的过程在左区间中中找到比右区间各个值小的最大值和比右区间各个值大的最小值,由于分治之后两边都已经排序完毕了,所以每一部分的更新复杂度只有O(N),具体还是看一下代码。
CDQ分治:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5e4+7;
const int INF = 0x3f3f3f3f;
struct STA{
int val,id;
}sta[MAXN],tmp[MAXN];
int n,ans[MAXN];
void CDQ(int l,int r){
if(l==r) return;
int mid = (l+r)>>1;
CDQ(l,mid); CDQ(mid+1,r);
int i=l,j=mid+1,now=l;
while(i<=mid&&j<=r){
if(sta[i].val<=sta[j].val) tmp[now++] = sta[i++];
else{
if(i!=l) ans[sta[j].id] = min(ans[sta[j].id],sta[j].val-sta[i-1].val);
ans[sta[j].id] = min(ans[sta[j].id],sta[i].val-sta[j].val);
tmp[now++] = sta[j++];
}
}
while(i<=mid) tmp[now++] = sta[i++];
while(j<=r){
ans[sta[j].id] = min(ans[sta[j].id],sta[j].val-sta[mid].val);
tmp[now++] = sta[j++];
}
for(int i=l;i<=r;i++) sta[i] = tmp[i];
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1588/4.in","r",stdin);
#endif
scanf("%d",&n);
memset(ans,INF,sizeof(ans));
for(int i=1;i<=n;i++){
scanf("%d",&sta[i].val);
sta[i].id = i;
}
ans[1] = sta[1].val;
CDQ(1,n);
int res = 0;
for(int i=1;i<=n;i++) res+=ans[i];
printf("%d\n",res);
#ifndef ONLINE_JUDGE
freopen("1588/4.out","r",stdin);
scanf("%d",&res);
printf("RESAULT:%d\n",res);
#endif
return 0;
}
Splay:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+7;
const int INF = 0x3f3f3f3f;
int n;
class SPLAY{
#ifndef root
#define root ch[0][1]
private:
int fa[MAXN],ch[MAXN][2],cnt[MAXN],val[MAXN],tot;
int chk(int rt){ return rt==ch[fa[rt]][1]; }
void rorate(int rt){
int f=fa[rt],gf=fa[f],d=chk(rt);
ch[gf][chk(f)]=rt; fa[rt]=gf;
ch[f][d]=ch[rt][d^1]; fa[ch[rt][d^1]]=f;
ch[rt][d^1]=f;fa[f]=rt;
}
int CreateNode(int v,int f){
tot++;
fa[tot] = f,val[tot] = v,cnt[tot] = 1;
return tot;
}
void splay(int rt,int to){
to = fa[to];
while(fa[rt]!=to){
int f = fa[rt],gf = fa[f];
if(gf==to){
rorate(rt);
return;
}
if(chk(rt)==chk(f)) rorate(f);
else rorate(rt);
rorate(rt);
}
}
public:
int find(int x){
int rt = root;
while(rt){
if(val[rt]==x) break;
else if(val[rt]>x) rt = ch[rt][0];
else rt = ch[rt][1];
}
return rt;
}
void Insert(int x){
if(!root){
root = CreateNode(x,0);
return;
}
int rt = root;
while(true){
if(val[rt]==x){
cnt[rt]++;
splay(rt,root);
return;
}
else if(val[rt]>x){
if(!ch[rt][0]){
ch[rt][0] = CreateNode(x,rt);
splay(ch[rt][0],root);
return;
}
rt = ch[rt][0];
}
else if(val[rt]<x){
if(!ch[rt][1]){
ch[rt][1] = CreateNode(x,rt);
splay(ch[rt][1],root);
return;
}
else rt = ch[rt][1];
}
}
}
int pre(int x){
int rt = ch[root][0];
if(!rt) return -INF;
while(ch[rt][1]) rt = ch[rt][1];
return val[rt];
}
int suf(int x){
int rt = ch[root][1];
if(!rt) return INF;
while(ch[rt][0]) rt = ch[rt][0];
return val[rt];
}
int match(int x){
if(find(x)) return 0;
Insert(x);
return min(x-pre(x),suf(x)-x);
}
#endif
}SPT;
int main(){
#ifndef ONLINE_JUDGE
freopen("1588/2.in","r",stdin);
#endif
scanf("%d",&n);
int ans = 0;
bool fst = true;
while(n--){
int x;
scanf("%d",&x);
if(fst){
fst = false;
ans+=x;
SPT.Insert(x);
}
else ans+=SPT.match(x);
}
printf("%d\n",ans);
#ifndef ONLINE_JUDGE
freopen("1588/2.out","r",stdin);
scanf("%d",&ans);
printf("RESAULT:%d\n",ans);
#endif
return 0;
}