bzoj 4864: [BeiJing 2017 Wc]神秘物质 splay

题意

给一个序列,要求资瓷如下操作:
merge x e 当前第 x 个元素和第 x+1 个元素合并,得到权值为 e 的新元素;
insert x e 在当前第 x 个元素和第 x+1 个元素之间插入一个权值为 e 的新元素。
max x y 当前第 x 到第 y 个元素之间的任意子区间中区间极差的最大值;
min x y 当前第 x 到第 y 个元素之间的任意子区间中区间极差的最小值。
n,m<=100000,a[i]<=10^9

分析

要求插入删除的话,线段树就不能做了吧。于是我们就可以上平衡树了。但由于要求区间查询,于是我们只能选择splay或可持久化treap了。我用的是splay。
最大极差的话就维护最大最小值就好了。
最小极差的话就维护相邻两点的最小值就好了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int N=100005;
const int inf=1e9;

int n,m,tot,a[N],root;
struct tree{int ans,mn,mx,val1,val2,l,r,fa,size;}t[N*2];

void updata(int x)
{
    t[x].mx=max(t[x].val1,max(t[t[x].l].mx,t[t[x].r].mx));
    t[x].mn=min(t[x].val1,min(t[t[x].l].mn,t[t[x].r].mn));
    t[x].ans=min(t[x].val2,min(t[t[x].l].ans,t[t[x].r].ans));
    t[x].size=t[t[x].l].size+t[t[x].r].size+1;
}

void rttr(int x)
{
    int y=t[x].l;
    if (x==root) root=y;
    t[x].l=t[y].r;t[t[y].r].fa=x;
    if (x==t[t[x].fa].l) t[t[x].fa].l=y;
    else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
    t[y].fa=t[x].fa;
    t[x].fa=y;t[y].r=x;
    updata(x);updata(y);
}

void rttl(int x)
{
    int y=t[x].r;
    if (x==root) root=y;
    t[x].r=t[y].l;t[t[y].l].fa=x;
    if (x==t[t[x].fa].l) t[t[x].fa].l=y;
    else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
    t[y].fa=t[x].fa;
    t[x].fa=y;t[y].l=x;
    updata(x);updata(y);
}

void splay(int x,int y)
{
    while (t[x].fa!=y)
    {
        int p=t[x].fa,g=t[p].fa;
        if (g==y)
        {
            if (x==t[p].l) rttr(p);
            else rttl(p);
            return;
        }
        if (x==t[p].l)
            if (p==t[g].l) rttr(g),rttr(p);
            else rttr(p),rttl(g);
        else
            if (p==t[g].r) rttl(g),rttl(p);
            else rttl(p),rttr(g);
    }
}

int kth(int k)
{
    if (k>t[root].size) return 0;
    int x=root;
    while (x)
    {
        if (t[t[x].l].size+1==k) return x;
        if (t[t[x].l].size>=k) x=t[x].l;
        else k-=t[t[x].l].size+1,x=t[x].r;
    }
}

void ins(int pos,int val1,int val2)
{
    t[++tot].val1=val1;t[tot].val2=val2;t[tot].size=1;
    if (!root)
    {
        root=tot;return;
    }
    int x=kth(pos-1),y=kth(pos);
    if (!t[x].r) t[tot].fa=x,t[x].r=tot;
    else t[tot].fa=y,t[y].l=tot;
    splay(tot,0);
}

void del(int x)
{
    int y=t[x].l+t[x].r;
    if (root==x) root=y;
    if (x==t[t[x].fa].l) t[t[x].fa].l=y;
    else t[t[x].fa].r=y;
    if (y) t[y].fa=t[x].fa;
    if (t[x].fa) splay(t[x].fa,0);
}

int main()
{
    t[0].mn=t[0].ans=inf;t[0].mx=-inf;
    scanf("%d%d",&n,&m);
    ins(1,0,0);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=n;i++) ins(i+1,a[i],abs(a[i]-a[i+1]));
    ins(n+2,0,0);
    while (m--)
    {
        char ch[10];int x,y;
        scanf("%s%d%d",ch,&x,&y);
        if (ch[1]=='e')
        {
            int p=kth(x+1),q=kth(x+2),w=kth(x+3),z=kth(x);
            t[z].val2=abs(t[z].val1-y);splay(z,0);
            if (!t[p].r) del(p),t[q].val1=y,t[q].val2=abs(y-t[w].val1),splay(q,0);
            else del(q),t[p].val1=y,t[p].val2=abs(y-t[w].val1),splay(p,0);
        }
        else if (ch[0]=='i')
        {
            int q=kth(x+1);t[q].val2=abs(t[q].val1-y);splay(q,0);
            if (x==t[root].size-2)
            {
                ins(x+2,y,0);continue;
            }
            int p=kth(x+2);
            ins(x+2,y,abs(y-t[p].val1));
        }
        else if (ch[1]=='a')
        {
            int p=kth(x),q=kth(y+2);
            splay(p,0);splay(q,p);
            printf("%d\n",t[t[q].l].mx-t[t[q].l].mn);
        }
        else
        {
            int p=kth(x),q=kth(y+1);
            splay(p,0);splay(q,p);
            printf("%d\n",t[t[q].l].ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值