[HNOI2002]营业额统计

Description
营业额统计Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况: 该天的最小波动值。当最小波动值越大时,就说明营业情况越不稳定。 而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。 第一天的最小波动值为第一天的营业额。
输入输出要求
Input
第一行为正整数 ,表示该公司从成立一直到现在的天数,接下来的 n 行每行有一个整数(有可能有负数) ,表示第i天公司的营业额。
天数 n<=32767 ,每天的营业额 ai<=1,000,000
最后结果 T<=231

Output
输出文件仅有一个正整数,即 。结果小于 231

Sample Input
6
5
1
2
5
4
6

Sample Output
12

HINT
结果说明: 5+|15|+|21|+|55|+|45|+|65|=5+4+1+0+1+1=12
该题数据bug已修复.—-2016.5.15

Source

思路
BST裸题,只需要插入一个点,求它的前驱和后继,然后比较这个点与前驱和后继差值的大小。

代码(splay)

#include <cstdio>
#include <algorithm>
#include <cstring>

const int maxn=100000;

int ans;

struct splay_tree
{
  int son[2][maxn+10],fa[maxn+10],tot,val[maxn+10],root;

  inline int mem()
  {
    val[0]=-1;
    return 0;
  }

  inline int t(int now)
  {
    return son[1][fa[now]]==now;
  }

  inline int rotate(int now)
  {
    int k=t(now),father=fa[now];
    if(son[!k][now])
      {
        fa[son[!k][now]]=father;
      }
    son[k][father]=son[!k][now];
    son[!k][now]=father;
    fa[now]=fa[father];
    if(fa[father])
      {
        son[t(father)][fa[father]]=now;
      }
    fa[father]=now;
    return 0;
  }

  inline int splay(int now,int c)
  {
    while(fa[now]!=c)
      {
        int f=fa[now],a=fa[f];
        if(a==c)
          {
            rotate(now);
          }
        else if(t(now)==t(f))
          {
            rotate(f);
            rotate(now);
          }
        else
          {
            rotate(now);
            rotate(now);
          }
      }
    if(!c)
      {
        root=now;
      }
    return 0;
  }

  inline int insert(int v)
  {
    ++tot;
    val[tot]=v;
    if(!root)
      {
        root=1;
        fa[1]=0;
        return 0;
      }
    int now=root;
    while(now)
      {
        int t=(val[now]<v);
        if(!son[t][now])
          {
            son[t][now]=tot;
            fa[tot]=now;
            break;
          }
        now=son[t][now];
      }
    splay(tot,0);
    return 0;
  }

  inline int prei(int now)
  {
    splay(now,0);
    int x=son[0][now];
    while(son[1][x])
      {
        x=son[1][x];
      }
    return x;
  }

  inline int nexti(int now)
  {
    splay(now,0);
    int x=son[1][now];
    while(son[0][x])
      {
        x=son[0][x];
      }
    return x;
  }

  inline int calc(int x)
  {
    insert(x);
    int p=val[prei(tot)],n=val[nexti(tot)];
    x=val[root];
    if((p==-1)&&(n==-1))
      {
        ans+=x;
      }
    else if(p==-1)
      {
        ans+=n-x;
      }
    else if(n==-1)
      {
        ans+=x-p;
      }
    else
      {
        ans+=std::min(n-x,x-p);
      }
    return 0;
  }
};

splay_tree st;
int n,a;

int main()
{
  scanf("%d",&n);
  st.mem();
  while(scanf("%d",&a)!=EOF)
    {
      st.calc(a);
      --n;
    }
  while(n--)
    {
      st.calc(0);
    }
  printf("%d\n",ans);
  return 0;
}

代码(fhq_treap)

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;

typedef pair<int,int> pii;

const int sor='y'+'c'+'z'+' '+'i'+'s'+' '+'o'+'u'+'r'+' '+'s'+'u'+'n';

struct treap
{ 
  int tot,root,son[3000009][2],size[3000009],val[3000009];

  int mem()
  {
    memset(val,255,sizeof(val));
    return 0;
  }

  int updata(int a)
  {
    return size[a]=size[son[a][0]]+size[son[a][1]]+1;
  }

  int random(int limit)
  {
    return rand()%limit+1;
  }

  int merge(int a,int b) 
  {
    if ((a==0)||(b==0))
      {
        return a+b;
      }
    if (random(size[a]+size[b])<=size[a])
      {
        son[a][1]=merge(son[a][1],b);
        updata(a);
        return a;
      }
    else
      {
        son[b][0]=merge(a,son[b][0]);
        updata(b);
        return b;
      }
  }

  pii split(int a,int k)
  {
    if (size[a]==k)
      {
        return make_pair(a,0);
      }
    if (k==0)
      {
        return make_pair(0,a);
      }
    pii t;
    if (size[son[a][0]]>=k)
      {
        t=split(son[a][0],k);
        son[a][0]=t.second;
        updata(a);
        return make_pair(t.first,a);
      }
    else
      {
        t=split(son[a][1],k-size[son[a][0]]-1);
        son[a][1]=t.first;
        updata(a);
        return make_pair(a,t.second);
      }
  }

  int rank(int v)
  {
    int i=root,ans=0;
    while (i!=0)
      {
        if (val[i]>=v)
          {
            i=son[i][0];
          }
        else
          {
            ans+=size[son[i][0]]+1;
            i=son[i][1];
          }
      }
    return ans+1;
  }

  int id(int v,int k)
  {
    if (k==0)
      {
        return 0;
      }
    if (size[son[v][0]]>=k)
      {
        return id(son[v][0],k);
      }
    if (size[son[v][0]]+1==k)
      {
        return v;
      }
    return id(son[v][1],k-size[son[v][0]]-1);
  }

  int getval(int v)
  {
    return val[id(root,v)];
  }

  int pre(int v)
  {
    return val[id(root,rank(v)-1)];
  }

  int next(int v)
  {
    return val[id(root,rank(v)+1)];
  }

  int insert(int v)
  {
    tot++;
    son[tot][0]=son[tot][1]=0;
    val[tot]=v;
    size[tot]=1;
    pii t=split(root,rank(v)-1);
    root=merge(merge(t.first,tot),t.second);
    return root;
  }

  int adelete(int v)
  {
    int x;
    x=rank(v);
    pii s,t;
    s=split(root,x-1);
    t=split(s.second,1);
    root=merge(s.first,t.second);
    return root;
  }
};

treap tree;
int n,x,pr,ne,ans;

int main()
{
  tree.mem();
  srand(sor);
  scanf("%d",&n);
  while (n--)
    {
      scanf("%d",&x); 
      tree.insert(x);
      pr=tree.pre(x);
      ne=tree.next(x);
      if (pr==-1&&ne==-1)    
        {
          ans+=x;
          continue;
        }
      if (ne==-1)    
        {
          ans+=abs(pr-x);
          continue;
        }
      if (pr==-1)
        {
          ans+=abs(ne-x);
          continue;
        }
      ans+=min(abs(ne-x),abs(pr-x));
    }
  printf("%d",ans);
  return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值