[bzoj1588][Splay]营业额统计

6 篇文章 0 订阅

Description

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

Input

第一行为正整数 ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数(有可能有负数) ,表示第i 天公司的营业额。
天数n<=32767, 每天的营业额ai <= 1,000,000。 最后结果T<=2^31

Output

输出文件仅有一个正整数,即Sigma(每天最小的波动值) 。结果小于2^31 。

Sample Input

6
5
1
2
5
4
6

Sample Output

12

HINT

结果说明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12

该题数据bug已修复.—-2016.5.15

题解

我哭了我再也不装逼写01Tire了
写了一个晚上的01Tire,结果还是没过,发现数据有,有,有负数。。
超级想哭的
Splay就水啦直接找前驱后继。。
贴个模版挖个坑
以后强了再来写01Tire

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct trnode
{
    int d;//int n;//重复节点个数
    int c;//控制的人数
    int f;//父亲
    int son[2];//儿子
}tr[110000];int len;bool bk;
int root;//目前的皇帝 
void update(int x)
{
    int lc=tr[x].son[0],rc=tr[x].son[1];
    tr[x].c=tr[lc].c+tr[rc].c+tr[x].n;
    //自身控制的人数是  左孩子控制的人数  加上  右孩子控制的人数  再加上和  我同名的人数 
}
void add(int d,int f)//增加一个值为d的节点,作为f的儿子
{
    len++;
    tr[len].d=d; tr[len].n=1; tr[len].c=1;//目前只知道有一个重复的,一个控制的
    tr[len].f=f; if(d<tr[f].d) tr[f].son[0]=len; else tr[f].son[1]=len;//父亲为f,f也认他为儿子 
    tr[len].son[0]=tr[len].son[1]=0;//儿子暂时没有 
}
void rotate(int x,int w)//零左旋转 一右旋转 
{
    int f=tr[x].f,ff=tr[f].f;
    int R,r;//大R要成为父亲,小r要成为儿子 

    R=f; r=tr[x].son[w];
    tr[R].son[1-w]=r;//我爸爸的儿子设置为我原来的 
    if(r!=0) tr[r].f=R;

    R=ff; r=x;
    if(tr[R].son[0]==f) tr[R].son[0]=r; else tr[R].son[1]=r;
    tr[r].f=R;//然后把我自己设置为我原来爷爷的儿子 

    R=x; r=f;
    tr[R].son[w]=r;
    tr[r].f=R;
    update(f); update(x);
}
void splay(int x,int rt)//将x变成rt的其中一个儿子
{
    while(tr[x].f!=rt)
    {
        int f=tr[x].f,ff=tr[f].f;
        if(ff==rt)//如果我祖父就是rt的话,那么只用旋转一次
        {
            if(tr[f].son[0]==x) rotate(x,1);else rotate(x,0);
        }
        else
        {
            if(tr[ff].son[0]==f && tr[f].son[0]==x){ rotate(f,1); rotate(x,1);}
            else if(tr[ff].son[1]==f && tr[f].son[1]==x){ rotate(f,0); rotate(x,0);}
            else if(tr[ff].son[0]==f && tr[f].son[1]==x){ rotate(x,0); rotate(x,1);}
            else if(tr[ff].son[1]==f && tr[f].son[0]==x){ rotate(x,1); rotate(x,0);}   
        }
    }
    if(rt==0) root=x;//如果我父亲就是上帝,那么我就是皇帝 
}
int findip(int d)//找值为 d 的节点
{
    int x=root;//从最顶端开始
    while(tr[x].d!=d)
    {
        if(d<tr[x].d)//如果他小于tr[x].d(左边一定比tr[x].d小)
        {
            if(tr[x].son[0]==0) break;//但是如果没有左孩子,那么就到底
            else x=tr[x].son[0]; 
        }
        else
        {
            if(tr[x].son[1]==0) break;//同理,没有右孩子一样到底
            else x=tr[x].son[1]; 
        }
    }
    return x;//这时候一定到了最接近的 
}
void ins(int d)
{
    if(root==0){add(d,0);root=len; return ;}
    int x=findip(d);//找最接近d的节点
    if(d==tr[x].d)
    {
        bk=true;
        tr[x].n++;//同名的加一个
        update(x); 
        splay(x,0);//把最近一个查找的变成根节点 
    }
    else
    {
        add(d,x);//那么把d作为x的儿子
        update(x);
        splay(len,0);//把len(  d  )变成根节点 
    }
}
void del(int d)
{
    int x=findip(d); splay(x,0);
    if(tr[x].n>1){tr[x].n--; update(x); return ;}//多一个的话,直接删除一个 

    if(tr[x].son[0]==0 && tr[x].son[1]==0) {root=0; len=0;}//如果都是0的话,那么直接删除树 
    else if(tr[x].son[0]==0 && tr[x].son[1]!=0){root=tr[x].son[1]; tr[root].f=0;}
    else if(tr[x].son[0]!=0 && tr[x].son[1]==0){root=tr[x].son[0]; tr[root].f=0;}
    else//都不为0 
    {
        int p=tr[x].son[0];while(tr[p].son[1]!=0)p=tr[p].son[1];splay(p,x);
        int R=p,r=tr[x].son[1];
        tr[R].son[1]=r;
        tr[r].f=R;
        root=R; tr[R].f=0;
        update(R);
    }
}
void findpaiming(int d)
{
    int x=findip(d); splay(x,0);
    printf("%d\n",tr[tr[x].son[0]].c+1);
}
void findshuzi(int k)
{
    int x=root;
    while(1)
    {
        int lc=tr[x].son[0],rc=tr[x].son[1];
        if(k<=tr[lc].c) x=lc;
        else if(k>tr[lc].c+tr[x].n){k-=tr[lc].c+tr[x].n; x=rc;}
        else break;
    }
    splay(x,0);
    printf("%d\n",tr[x].d);
}
int findqianqu(int d)
{
    int x=findip(d); splay(x,0);
    if(d<=tr[x].d)
    {
        x=tr[x].son[0];
        while(tr[x].son[1]!=0) x=tr[x].son[1];
    }
    return tr[x].d;
}
int findhouji(int d)
{
    int x=findip(d); splay(x,0);
    if(tr[x].d<=d)
    {
        x=tr[x].son[1];
        while(tr[x].son[0]!=0) x=tr[x].son[0];
    }
    return tr[x].d;
}
int mymin(int x,int y){return x>y?y:x;}
int main()
{
    int n;
    int aa[21000];
    scanf("%d",&n);
    root=0; len=0;
    int ans=0;
    int x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        bk=false;ins(x);
        if(i==1) {ans+=x; continue;}
        else
        {
            if(bk==true){continue;}
            int kk=findqianqu(x),mm=findhouji(x);
            ans+=mymin(abs(x-kk),abs(x-mm));
        }
    }
    printf("%d\n",ans);
    return 0;
}

Wa的01Tire

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
    int c[2],l,r;
    node(){c[0]=c[1]=-1;}
}tr[5110000];int rt,trlen;
int b[25],a[25],ln;
void get(int x)
{
    int len=0;
    int tmp=x;
    while(tmp)
    {
        len++;
    //  if(x%2==1)b[ln]=1;
        //else b[ln]=0;
        tmp/=2;
    }
    tmp=x;ln=0;
    while(tmp)
    {
        ln++;
        if(tmp%2==1)b[len-ln+1]=1;
        else b[len-ln+1]=0;
        tmp/=2;
    }
    memset(a,0,sizeof(a));
    for(int i=1;i<=ln;i++)a[i+23-ln]=b[i];
}
void add()
{
    int p=rt;
    for(int i=1;i<=23;i++)
    {
        if(a[i]==0){tr[p].l++;if(tr[p].c[0]==-1)tr[p].c[0]=++trlen;p=tr[p].c[0];}
        else {tr[p].r++;if(tr[p].c[1]==-1)tr[p].c[1]=++trlen;p=tr[p].c[1];}
    }
}
int q[25];
int find_rk()
{
    int p=rt,ret=0;
    if(a[1]==0)
    {
        if(tr[p].c[0]==-1)return 1;
        else p=tr[p].c[0];
    }
    if(a[1]==1)
    {
        if(tr[p].c[1]==-1)return 1;
        else p=tr[p].c[1];
    }
    for(int i=1;i<=23;i++)
    {
        if(a[i+1]==0)
        {
            if(tr[p].c[0]==-1)break;
            p=tr[p].c[0];
        }
        else
        {
            ret+=tr[p].l;
            if(tr[p].c[1]==-1)break;
            p=tr[p].c[1];
        }
    }
    return ret+1;
}
int fd(int k)//排第k的数 
{
    int p=rt,sum=0,ret=0;
    for(int i=1;i<=23;i++)
    {
        if(p==-1)break;
        if(sum+tr[p].l<k)sum+=tr[p].l,p=tr[p].c[1],ret+=(1<<(23-i));
        else p=tr[p].c[0];
    }
//  printf(" %d\n",ret);
    return ret;
}
int main()
{
//  freopen("turnover.IN4","r",stdin);
    int n,ans=0;
    scanf("%d",&n);
    rt=0;
    for(int i=1;i<=n;i++)
    {
        int x;scanf("%d",&x);
        get(x);
        if(i==1)ans=x,add();
        else
        {
            int rk=find_rk();
            //if(rk>i)printf(" NO\n");
        //  printf(" %d\n",rk);
            int u=fd(rk-1),v=fd(rk);
            if(u==0)u=999999999;
            int tmp=min(abs(x-u),abs(x-v));
            if(rk<i)tmp=min(tmp,abs(x-fd(rk+1)));
            ans+=tmp;
            //printf(" %d\n",ans);
            add();
        }
    }
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值