【HNOI2002】【BZOJ 1588】营业额统计

Description

读一个数,求出前面的所有数与这个数的相差最小是多少。
N105

Analysis

线段树可以做,然而我用来splay练手
原本我不会模板,自己乱打,不成体统,这是下面是alan教我的方法
读入就insert,求出前驱后继,分别比较去较小,累计到答案。
insert是递归版的,大概就是在splay上面二分。
求pre和suf就把x旋到根,从根往下走即可。

Code

#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=100010,INF=2147483647;
int n,p,q,root,tot,f[N],t[N][2],key[N];
bool pd(int x)
{
    return x==t[f[x]][1];
}
void insert(int &x,int y,int fa)
{
    if(!x)
    {
        x=++tot,key[x]=y,f[x]=fa;
        return;
    }
    if(y0],y,x);
    else insert(t[x][1],y,x);
}
void rotate(int x)
{
    int y=f[x],z=pd(x);
    t[y][z]=t[x][1-z];
    if(t[x][1-z]) f[t[x][1-z]]=y;
    f[x]=f[y];
    if(f[y]) t[f[y]][pd(y)]=x;
    f[y]=x,t[x][1-z]=y;
}
void splay(int x,int y)
{
    while(f[x]!=y)
    {
        if(f[f[x]]!=y)
            if(pd(x)==pd(f[x])) rotate(f[x]);
            else rotate(x);
        rotate(x);
    }
    if(!y) root=x;
}
int pre(int x)
{
    for(x=t[x][0];t[x][1];x=t[x][1]);
    return x;
}
int suf(int x)
{
    for(x=t[x][1];t[x][0];x=t[x][0]);
    return x;
}
int main()
{
    int x,ans;
    scanf("%d",&n);
    scanf("%d",&x);
    ans=x;
    insert(root,x,0);
    fo(i,2,n)
    {
        scanf("%d",&x);
        insert(root,x,0);
        splay(tot,0);
        int l=pre(root);
        if(!l) p=INF;else p=x-key[l];
        int r=suf(root);
        if(!r) q=INF;else q=key[r]-x;
        ans+=min(p,q);
    }
    printf("%d",ans);
    return 0;
}

你可能感兴趣的:(题解,splay)