【例题】Splay

40 篇文章 0 订阅
22 篇文章 0 订阅

NKOJ 1925【平衡树】营业额统计
时间限制 : 10000 MS 空间限制 : 65536 KB

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

输入格式
第一行为正整数n(n<=32767),表示该公司从成立一直到现在的天数,
接下来的n行每行有一个整数ai(ai<=1000000),表示第i天公司的营业额。

输出格式
仅有一个正整数,即Sigma(每天最小的波动值) 。结果小于231

样例输入
6
5
1
2
5
4
6

样例输出
12

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

来源 HNOI2002

左右伸展操作、splay、插入、找前驱后驱。

#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
const int need=1e6+3;

//........................................................
int root=0,tot;
int fa[need],ls[need],rs[need],si[need],val[need];

void sr(int x)
{
    int y=fa[x],z=fa[y];
    ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z;
    ls[y]=rs[x]; fa[rs[x]]=y;
    rs[x]=y; fa[y]=x;
    si[x]=si[y],si[y]=si[ls[y]]+si[rs[y]]+1;
}
void sl(int x)
{
    int y=fa[x],z=fa[y];
    ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z;
    rs[y]=ls[x]; fa[ls[x]]=y;
    ls[x]=y; fa[y]=x;
    si[x]=si[y],si[y]=si[ls[y]]+si[rs[y]]+1;
}
void splay(int x)
{
    int y;
    while(fa[x])
    {
        y=fa[x];
        if(ls[y]==x) sr(x);
        else sl(x);
    }
    root=x;
} 
void insert(int d)
{
    if(tot==0)
    {
        val[tot=root=1]=d;
        si[root]=1;
        ls[root]=rs[root]=fa[root]=0;
        return ;
    }
    tot++;
    int p=root;
    while(true)
    {
        si[p]++;
        if(d<val[p])
         if(ls[p]) p=ls[p];
         else{ls[p]=tot;break;}
        else 
         if(rs[p]) p=rs[p];
         else{rs[p]=tot;break;}
    }
    val[tot]=d,fa[tot]=p,si[tot]=1;
    splay(tot);
}
int getmin(int p)
{
    while(ls[p]) p=ls[p];
    return val[p];
}
int getmax(int p)
{
    while(rs[p]) p=rs[p];
    return val[p];
}


int main()
{
    int ans=0,n;scanf("%d",&n);
    bool markb=0,markc=0;
    for(int i=1,a,b,c,t;i<=n;i++) 
    {
        scanf("%d",&a);
        insert(a);
        if(ls[root]) 
        {
            b=getmax(ls[root]);
            markb=true;
        }
        if(rs[root])
        {
            c=getmin(rs[root]);
            markc=true;
        }
        if(markb&&markc) ans+=min(abs(b-a),abs(c-a));
        else if(markb) ans+=abs(b-a);
        else if(markc) ans+=abs(c-a); 
        else ans+=a;
    }
    cout<<ans; 
}

NKOJ3710 k-number
时间限制 : - MS 空间限制 : 128000 KB
评测说明 : 每组测试数据1000ms

问题描述
给定一个初始为空的序列,支持Q次操作
1 a 表示向序列中加入一个值为a的数
2 k 表示查询序列中第k小的数

输入格式
第一行一个整数Q
接下来Q行,每行两个整数代表依次操作

输出格式
对于每一个询问,输出一行,表示答案

样例输入
5
1 1
1 3
2 1
1 4
2 3

样例输出
1
4

提示
Q<=50000
1<=a<=10000000
输入保证第k小数存在且每个数互不相同

找k大

#include<cstdio>
#include<iostream>
using namespace std;
const int need=2000005;

//.............................................
inline void in_(int &d)
{
    char t=getchar();bool mark=0;
    while(t<'0'||t>'9') {if(t=='-') mark=1;t=getchar();}
    for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';if(mark) d=-d;
}
inline void out_(int x)
{
    if(x<0) {x=-x;putchar('-');}
    if(x>=10) out_(x/10);
    putchar(x%10+'0');
}
//.............................................
int tot,root;
int fa[need],ls[need],rs[need],si[need],val[need];

void sr(int x)
{
    int y=fa[x],z=fa[y];
    ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z;
    ls[y]=rs[x]; fa[rs[x]]=y;
    rs[x]=y; fa[y]=x;
    si[x]=si[y];si[y]=si[ls[y]]+si[rs[y]]+1;
}
void sl(int x)
{
    int y=fa[x],z=fa[y];
    ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z;
    rs[y]=ls[x]; fa[ls[x]]=y;
    ls[x]=y; fa[y]=x;
    si[x]=si[y];si[y]=si[ls[y]]+si[rs[y]]+1;
}
void splay(int x)
{
    int y;
    while(fa[x])
    {
        y=fa[x],z=fa[y];
        if(ls[y]==x) sr(x);
        else sl(x);
    }
    root=x;
}
void insert(int d)
{
    if(tot==0)
    {
        val[tot=root=1]=d;
        si[root]=1;
        ls[root]=rs[root]=fa[root]=0;
        return ;
    }
    tot++;
    int p=root;
    while(true)
    {
        si[p]++;
        if(d<val[p])
         if(ls[p]) p=ls[p];
         else{ls[p]=tot;break;}
        else
         if(rs[p]) p=rs[p];
         else{rs[p]=tot;break;}
    }
    val[tot]=d;fa[tot]=p;si[tot]=1;
    splay(tot);
}
int getk(int k)
{
    int p=root;
    while(true)
    {
        if(ls[p]&&si[ls[p]]>=k) p=ls[p];
        else if((ls[p]&&si[ls[p]]==k-1)||k==1) return val[p];
        else {k-=si[ls[p]]+1;p=rs[p];}
    }
}

int main()
{
    int q;scanf("%d",&q);
    int a,b;
    while(q--)
    {
        in_(a),in_(b);
        if(a==1) insert(b);
        else out_(getk(b)),putchar(10);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值