[BJWC2017][JZOJ4986]神秘物质

本文介绍了一种基于Splay树的数据结构实现,用于解决特定序列操作问题,包括插入、删除及查询极差等操作。文章提供了完整的代码实现,并分析了算法的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

有个序列,一开始有n个元素{Ei},你需要维护以下几种操作:
merge x e: 删掉第x+1个数并将第i个数改为e
insert x e: 在第x个数后面插入一个e
max x y: 询问当前区间[x,y]内任意长度大于1的子区间中极差的最大值
min x y询问当前区间[x,y]内任意长度大于1的子区间中极差的最小值
操作数为q

1n,q105,1e,Ei109


题目分析

显然max询问就是最大值减最小值,min询问就是相邻的差的最小值。
直接使用splay维护就好了,min询问的维护要想好,不然挺坑的。
时间复杂度O(nlogn)


代码实现

#include <iostream>
#include <climits>
#include <cstdio>
#include <cctype>

using namespace std;

inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}

int buf[30];

inline void write(int x)
{
    if (x<0) putchar('-'),x=-x;
    for (;x;x/=10) buf[++buf[0]]=x%10;
    if (!buf[0]) buf[++buf[0]]=0;
    for (;buf[0];putchar('0'+buf[buf[0]--]));
}

const int INF=INT_MAX;
const int N=100050;
const int Q=100050;
const int S=N+Q;

int e[N];
int n,q;

inline int abs(int x){return x>0?x:-x;}

struct SPLAY
{
    int son[S][2],fa[S],size[S],E[S],R[S],D[S],f[S][2],g[S];//E energy R right element D diff
    int tot,root;

    inline bool side(int x){return son[fa[x]][1]==x;}

    inline void update(int x)
    {
        if (!x) return;
        size[x]=size[son[x][0]]+size[son[x][1]]+1;
        R[x]=son[x][1]?R[son[x][1]]:E[x],g[x]=min(D[x],min(g[son[x][0]],g[son[x][1]]));
        f[x][0]=min(E[x],min(f[son[x][0]][0],f[son[x][1]][0])),f[x][1]=max(E[x],max(f[son[x][0]][1],f[son[x][1]][1]));
    }

    inline int newnode(int x,int y,int l,int r)
    {
        fa[++tot]=0,E[tot]=x,D[tot]=y;
        fa[l]=l?tot:0,fa[r]=r?tot:0,son[tot][0]=l,son[tot][1]=r;
        return update(tot),tot;
    }

    inline void rotate(int x)
    {
        int y=fa[x];bool s=side(x);
        if (fa[y]) son[fa[y]][side(y)]=x;
        if (son[x][s^1]) fa[son[x][s^1]]=y;
        son[y][s]=son[x][s^1],son[x][s^1]=y;
        fa[x]=fa[y],fa[y]=x;
        update(y),update(x);
    }

    inline void splay(int x,int y)
    {
        for (;fa[x]!=y;rotate(x))
            if (fa[fa[x]]!=y)
                if (side(x)==side(fa[x])) rotate(fa[x]);
                else rotate(x);
    }

    inline int kth(int x,int y)
    {
        if (size[son[x][0]]+1==y) return x;
        return size[son[x][0]]>=y?kth(son[x][0],y):kth(son[x][1],y-size[son[x][0]]-1);
    }

    inline void split(int x,int y,int &l,int &r)
    {
        if (!y) l=0,r=x;
        else splay(l=kth(x,y),0),r=son[l][1],son[l][1]=fa[r]=0,update(l);
    }

    inline void merge(int x,int y,int &rt)
    {
        if (!x) rt=y;
        else if (!y) rt=x;
        else splay(rt=kth(x,size[x]),0),son[fa[y]=rt][1]=y,update(rt);
    }

    inline int query(int l,int r,bool tp)
    {
        int x,y,mid,ret;
        split(root,r,x,y),split(x,l-(tp^1),x,mid),ret=tp?g[mid]:f[mid][1]-f[mid][0],merge(x,mid,x),merge(x,y,root);
        return ret;
    }

    inline void insert(int x,int y)
    {
        int l,r;
        split(root,x,l,r),splay(r=kth(r,1),0),D[r]=abs(E[r]-y),update(r),root=newnode(y,abs(y-E[l]),l,r);
    }

    inline void extend(int x,int y)
    {
        int l,r;
        split(root,x,l,r);
        if (size[r]>1) splay(r=kth(r,2),0),fa[son[l][1]=r]=l,E[l]=y,D[l]=abs(E[l]-R[son[l][0]]),son[r][0]=0,D[r]=abs(E[l]-E[r]),update(r);
        update(root=l);
    }

    inline void init()
    {
        tot=0,E[tot]=R[tot]=g[tot]=f[tot][0]=INF,e[0]=INF;
        for (int i=1;i<=n;++i) root=newnode(e[i],abs(e[i]-e[i-1]),root,0);
        //splay(1,0),root=1;
    }
}t;

int main()
{
    freopen("atom.in","r",stdin),freopen("atom.out","w",stdout);
    n=read(),q=read();
    for (int i=1;i<=n;++i) e[i]=read();
    for (t.init();q--;)
    {
        char opt=getchar();
        while (!isalpha(opt)) opt=getchar();
        if (opt=='m')
        {
            opt=getchar();
            int x=read(),y=read();
            switch (opt)
            {
                case 'e':
                {
                    t.extend(x,y);
                    break;
                }
                case 'a':
                {
                    write(t.query(x,y,0)),putchar('\n');
                    break;
                }
                case 'i':
                {
                    write(t.query(x,y,1)),putchar('\n');
                    break;
                }
            }
        }
        else
        {
            int x=read(),e=read();
            t.insert(x,e);
        }
    }
    fclose(stdin),fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值