营业额统计 题解

营业额统计 题解

题面

思路

每插入一个数从前后找最小的数即可
最后一个求和搞定。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#define pk putchar(' ')
#define ph puts("")
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
template <class T>
void rd(T &x)
{
    x = 0;
    int f = 1;
    char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    x *= f;
}
template <class T>
void pt(T x)
{
    if (x < 0)
        putchar('-'), x = (~x) + 1;
    if (x > 9)
        pt(x / 10);
    putchar(x % 10 ^ 48);
}
template <class T>
T Max(T a, T b)
{
    return a > b ? a : b;
}
template <class T>
T Min(T a, T b)
{
    return a < b ? a : b;
}
using namespace std;
const int inf = 0x3f3f3f3f, N = (1 << 15);
int n, a[N], root, sum;
ll ans;
struct Treap 
{
    int l, r, v, num, size;
    ll rnd;
}t[N];
//用结构体存变量:
// l:左孩子,r:右孩子;
// v:该节点的权值;
// num:与该节点权值相同的点的个数;
// size:以该节点为根的子树的节点数;
// rnd:该节点的随机值;
void update(int p) 
{ 
    t[p].size = t[t[p].r].size + t[t[p].l].size + t[p].num; 
}  
//用子节点的值更新父节点的值;
void rt(int &p) 
{
    int q = t[p].l;
    t[p].l = t[q].r;
    t[q].r = p;
    t[q].size = t[p].size;
    update(p);
    p = q;
}
void lt(int &p) 
{
    int q = t[p].r;
    t[p].r = t[q].l;
    t[q].l = p;
    t[q].size = t[p].size;
    update(p);
    p = q;
}  
//基础的左旋右旋操作;
void ins(int &p, int x) 
{
    if (!p) 
    {
        p = ++sum;
        t[p].num = t[p].size = 1;
        t[p].v = x;
        t[p].rnd = rand();
        return;
    }
    t[p].size++;
    if (t[p].v == x)
        t[p].num++;
    else if (x > t[p].v) 
    {
        ins(t[p].r, x);
        if (t[t[p].r].rnd < t[p].rnd)
            lt(p);
    }
    //如果要插入的值比当前节点的值大,就将其插入右子树中,同时如果右节点的随机值比当前节点随机值小
    //就要通过左旋来维护堆的性质;
    else 
    {
        ins(t[p].l, x);
        if (t[t[p].l].rnd < t[p].rnd)
            rt(p);
    }//理由同上;
}
//插入操作
int fpre(int p, int x) 
{
    if (!p)
        return -inf;
    if (t[p].v > x)
        return fpre(t[p].l, x);
    else
        return Max(t[p].v, fpre(t[p].r, x));
}  
//查找前驱;
int fbac(int p, int x) 
{
    if (!p)
        return inf;
    if (t[p].v < x)
        return fbac(t[p].r, x);
    else
        return Min(t[p].v, fbac(t[p].l, x));
}  
//查找后继;
int query1(int p, int x)
{
    if (!p) 
        return 0;
    if (t[p].v == x) 
        return t[t[p].l].size + 1;
    if (x > t[p].v) 
        return t[t[p].l].size + t[p].num + query1(t[p].r, x);
    else 
        return query1(t[p].l, x);
}
//查询x数的排名;
int query2(int p, int x)
{
    if (!p) 
        return 0;
    if (x <= t[t[p].l].size) 
        return query2(t[p].l, x);
    x -= t[t[p].l].size;
    if (x <= t[p].num) 
        return t[p].v;
    x -= t[p].num;
    return query2(t[p].r, x);
}
//查询排名为x的数;
int main() 
{
    srand(*new unsigned);
    rd(n), rd(a[1]);
    ins(root, a[1]);
    ans = a[1];
    for (int i = 2; i <= n; i++) 
    {
        rd(a[i]);
        ans += Min(fabs(fpre(root, a[i]) - a[i]), fabs(fbac(root, a[i]) - a[i]));  
        //在前驱和后继中选一个符合题意的值来更新ans;
        ins(root, a[i]);                          
        //要先找后插入;
    }
    pt(ans);
    return 0;
}
原创文章 23 获赞 41 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43537070/article/details/103263747