[BeiJing 2017 Wc]神秘物质——Splay

题面

   Bzoj4864

解析

   合并序列相邻的两点,在序列中插入一个点,直接考虑Splay

  先考虑如何完成操作3, 4

  对于操作3,显然是区间最大减去区间最小,Splay维护一下即可

  对于操作4,实际上就是求区间内相邻两数的差的绝对值的最小值(注意是绝对值,我一开始就写错了), 那么每个节点还需要维护当前点与它前驱的差的绝对值,查询$[l, r]$的答案,实际上是在Splay的$[l+1, r]$节点中查询

  操作1:把x旋转至根,把x+2旋转至根的右儿子,x+1就是x+2的左儿子,直接删除。因为相邻两数的差也变了,所以先更新x+2的信息,再更新x的信息

  操作2:把x旋转至根,x+1就是它的后继,在后继的左儿子新开一个节点,存信息,相邻两数的差改变了,所以后继的信息也要更新,再把新开的节点旋转至根,完成整颗Splay的信息更新

 代码:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100004;

template<class T> void read(T &re)
{
    re=0;
    T sign=1;
    char tmp;
    while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;
    re=tmp-'0';
    while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');
    re*=sign;
}

int n, m, root, tot;
int a[maxn];

struct splay_tree{
    int fa, s[2], siz;
    int val, mx, mn, mu, b;
}tr[maxn<<1];

void update(int x)
{
    int ls = tr[x].s[0], rs = tr[x].s[1];
    tr[x].siz = tr[ls].siz + tr[rs].siz + 1;
    tr[x].mx = tr[x].mn = tr[x].val;
    tr[x].mu = tr[x].b;
    if(ls)
    {
        tr[x].mx = max(tr[x].mx, tr[ls].mx);
        tr[x].mn = min(tr[x].mn, tr[ls].mn);
        tr[x].mu = min(tr[x].mu, tr[ls].mu);
    }
    if(rs)
    {
        tr[x].mx = max(tr[x].mx, tr[rs].mx);
        tr[x].mn = min(tr[x].mn, tr[rs].mn);
        tr[x].mu = min(tr[x].mu, tr[rs].mu);
    }
}

void Rotate(int x)
{
    int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];
    tr[y].s[k] = son;tr[son].fa = y;
    tr[x].s[k^1] = y;tr[y].fa = x;
    tr[z].s[w] = x;tr[x].fa = z;
    update(y);update(x);
}

void Splay(int x, int to)
{
    int y, z;
    while(tr[x].fa != to)
    {
        y = tr[x].fa;
        z = tr[y].fa;
        if(z != to)
            Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y);
        Rotate(x);
    }
    if(!to)
        root = x;
}

void build(int l, int r, int ff)
{
    int mid = (l + r)>>1;
    if(l < mid)
        build(l, mid - 1, mid);
    if(mid < r)
        build(mid + 1, r, mid);
    if(ff)
        tr[ff].s[ff < mid] = mid;
    tr[mid].fa = ff;
    tr[mid].val = a[mid];
    tr[mid].b = abs(a[mid] - a[mid - 1]);
    update(mid);
}

int Find(int x)
{
    int now = root;
    while(1)
    {
        int ls = tr[now].s[0], rs = tr[now].s[1];
        if(x == tr[ls].siz + 1)
            return now;
        if(x > tr[ls].siz + 1)
            x -= tr[ls].siz + 1, now = rs;
        else
            now = ls;
    }
}

int Findpre()
{
    int now = tr[root].s[0];
    if(!now)    return 0;
    while(tr[now].s[1])     now = tr[now].s[1];
    return now;
}

int Findnxt()
{
    int now = tr[root].s[1];
    if(!now)    return 0;
    while(tr[now].s[0])     now = tr[now].s[0];
    return now;
}

int main()
{
    read(n);read(m);
    for(int i = 1; i <= n; ++i)
        read(a[i+1]);
    n += 2;
    build(1, n, 0);
    tr[0].s[1] = root = (1 + n)>>1;
    tot = n;
    for(int i = 1; i <= m; ++i)
    {
        char opt[8];
        scanf("%s", opt);
        if(opt[1] == 'e')
        {
            int x, e;
            read(x);read(e);
            x++;
            int now = Find(x);
            Splay(now, 0);
            int pre = Findpre();
            tr[now].b = abs(e - tr[pre].val);
            tr[now].val = e;
            int nnxt = Find(x + 2);
            Splay(nnxt, now);
            tr[nnxt].b = abs(tr[nnxt].val - e);
            tr[nnxt].s[0] = 0;
            update(nnxt);update(now);
        }
        else if(opt[0] == 'i')
        {
            int x, e;
            read(x);read(e);
            x++;
            int now = Find(x);
            Splay(now, 0);
            int nxt = Findnxt();
            tr[nxt].s[0] = ++tot;
            tr[tot].val = e;
            tr[tot].fa = nxt;
            tr[tot].b = abs(e - tr[now].val);
            tr[nxt].b = abs(tr[nxt].val - e);
            Splay(tot, 0);
        }
        else if(opt[1] =='a')
        {
            int x, y;
            read(x);read(y);
            x++;y++;
            x = Find(x - 1);
            y = Find(y + 1);
            Splay(x, 0);
            Splay(y, x);
            int now = tr[y].s[0];
            printf("%d\n", tr[now].mx - tr[now].mn);
        }
        else
        {
            int x, y;
            read(x);read(y);
            x += 2;
            y++;
            x = Find(x - 1);
            y = Find(y + 1);
            Splay(x, 0);
            Splay(y, x);
            int now = tr[y].s[0];
            printf("%d\n", tr[now].mu);
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Joker-Yza/p/11366924.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值