[BZOJ4864][BeiJing 2017 Wc]神秘物质(splay)

来源:互联网 发布:客源软件 编辑:程序博客网 时间:2024/04/28 05:02

题目描述

传送门

题目大意:
有一列数列,支持以下操作
对于一列数,相邻一段中最大和最小的两个数的差值称为区间极差。
merge x e 当前第 x 个数和第 x+1 个数合并,得到值为 e 的新数;
insert x e 在当前第 x 个数和第 x+1 个数之间插入一个能量为 e 的新数。
max x y 当前第 x 到第 y 个原子之间的任意子区间中区间极差的最大值;
min x y 当前第 x 到第 y 个原子之间的任意子区间中区间极差的最小值。

题解

用splay维护:子树大小,区间最大最小值,区间最左端最右端的数值,相邻两个元素差值的最小值
因为min操作实际上就是查询相邻两个元素差值的最小值
其余的随便做咯

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 200005#define inf 1000000001int n,m,root,sz,a[N];int f[N],ch[N][2],key[N],size[N],ls[N],rs[N],maxn[N],minn[N],cha[N];char opt[10];int Abs(int x){return (x>0)?x:-x;}void update(int x){    int l=ch[x][0],r=ch[x][1];    size[x]=1;cha[x]=inf;    maxn[x]=minn[x]=ls[x]=rs[x]=key[x];    if (l)    {        ls[x]=ls[l];size[x]+=size[l];        maxn[x]=max(maxn[x],maxn[l]);        minn[x]=min(minn[x],minn[l]);        cha[x]=min(cha[x],cha[l]);        cha[x]=min(cha[x],Abs(key[x]-rs[l]));    }    if (r)    {        rs[x]=rs[r];size[x]+=size[r];        maxn[x]=max(maxn[x],maxn[r]);        minn[x]=min(minn[x],minn[r]);        cha[x]=min(cha[x],cha[r]);        cha[x]=min(cha[x],Abs(key[x]-ls[r]));    }}int build(int l,int r,int fa){    if (l>r) return 0;    int mid=(l+r)>>1;    f[mid]=fa;key[mid]=a[mid];    int lch=build(l,mid-1,mid);    int rch=build(mid+1,r,mid);    ch[mid][0]=lch;ch[mid][1]=rch;    update(mid);    return mid;}int get(int x){return ch[f[x]][1]==x;}void rotate(int x){    int old=f[x],oldf=f[old],wh=get(x);    ch[old][wh]=ch[x][wh^1];    if (ch[old][wh]) f[ch[old][wh]]=old;    ch[x][wh^1]=old;    f[old]=x;    if (oldf) ch[oldf][ch[oldf][1]==old]=x;    f[x]=oldf;    update(old);    update(x);}void splay(int x,int tar){    for (int fa;(fa=f[x])!=tar;rotate(x))        if (f[fa]!=tar)            rotate((get(x)==get(fa))?fa:x);    if (!tar) root=x;}int find(int x){    int now=root;    while (1)    {        if (ch[now][0]&&size[ch[now][0]]>=x) now=ch[now][0];        else        {            if (ch[now][0]) x-=size[ch[now][0]];            if (x==1) return now;            --x;            now=ch[now][1];        }    }}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;++i) scanf("%d",&a[i+1]);    root=build(1,n+2,0);sz=n+2;    while (m--)    {        scanf("%s",opt);        if (opt[0]=='m'&&opt[1]=='e')        {            int x,e;scanf("%d%d",&x,&e);            // x x+1            int aa=find(x);            int bb=find(x+3);            splay(aa,0);            splay(bb,aa);            //delete            ch[ch[root][1]][0]=0;            //insert            ++sz;            f[sz]=ch[root][1];ch[ch[root][1]][0]=sz;            size[sz]=1;cha[sz]=inf;            key[sz]=maxn[sz]=minn[sz]=ls[sz]=rs[sz]=e;            update(ch[root][1]);            update(root);        }        else if (opt[0]=='i')        {            int x,e;scanf("%d%d",&x,&e);            //x,x+1            int aa=find(x+1);            int bb=find(x+2);            splay(aa,0);            splay(bb,aa);            //insert            ++sz;            size[sz]=1;cha[sz]=inf;            f[sz]=ch[root][1];ch[ch[root][1]][0]=sz;            key[sz]=maxn[sz]=minn[sz]=ls[sz]=rs[sz]=e;            update(ch[root][1]);            update(root);        }        else if (opt[0]=='m'&&opt[1]=='a')        {            int x,y;scanf("%d%d",&x,&y);            //x y            int aa=find(x);            int bb=find(y+2);            splay(aa,0);            splay(bb,aa);            //query            int now=ch[ch[root][1]][0];            printf("%d\n",maxn[now]-minn[now]);        }        else        {            int x,y;scanf("%d%d",&x,&y);            //x y            int aa=find(x);            int bb=find(y+2);            splay(aa,0);            splay(bb,aa);            //query            int now=ch[ch[root][1]][0];            printf("%d\n",cha[now]);        }    }}
0 0