[bzoj4864][BeiJing 2017 Wc]神秘物质

来自FallDream的博客,未经允许,请勿转载,谢谢。


21ZZ 年,冬。
小诚退休以后, 不知为何重新燃起了对物理学的兴趣。 他从研究所借了些实验仪器,整天研究各种微观粒子。这
一天, 小诚刚从研究所得到了一块奇异的陨石样本, 便迫不及待地开始观测。 在精密仪器的视野下,构成陨石
的每个原子都无比清晰。 小诚发现, 这些原子排成若干列, 每一列的结构具有高度相似性。于是,他决定对单
独一列原子进行测量和测试。被选中的这列共有 N 个顺序排列的原子。 最初, 第 i 个原子具有能量 Ei。 随着
时间推移和人为测试, 这列原子在观测上会产生两种变化:
merge x e 当前第 x 个原子和第 x+1 个原子合并,得到能量为 e 的新原子;
insert x e 在当前第 x 个原子和第 x+1 个原子之间插入一个能量为 e 的新原子。
对于一列原子,小诚关心的是相邻一段中能量最大和能量最小的两个原子的能量差值,
称为区间极差。 因此, 除了观测变化外,小诚还要经常统计这列原子的两类数据:
max x y 当前第 x 到第 y 个原子之间的任意子区间中区间极差的最大值;
min x y 当前第 x 到第 y 个原子之间的任意子区间中区间极差的最小值。
其中, 子区间指的是长度至少是 2 的子区间。
小诚坚信这项研究可以获得诺贝尔物理学奖。为了让小诚早日了结心愿,你能否帮助他实现上述的观测和测量呢?
n,m<=10^5
 
话说省夏监考的时候写题真刺激..
这道题其实是一道平衡树裸题,max操作显然是问区间最大值和最小值,min操作只要稍微脑补一下都能发现答案只可能是相邻两个相差的绝对值的最小值
所以只要开两个splay,一个维护原数组,另一个维护差分数组即可
#include<iostream>
#include<cstdio>
#define MN 200000
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}
int n,m,a[MN+5],b[MN+5];
inline int abs(int x){return x<0?-x:x;}
struct Splay
{
    int cnt,c[MN+5][2],fa[MN+5],size[MN+5],mx[MN+5],mn[MN+5],rt,s[MN+5];
    void update(int x)
    {
        int l=c[x][0],r=c[x][1];
        mx[x]=mn[x]=s[x];size[x]=size[l]+size[r]+1;
        if(l) mx[x]=max(mx[x],mx[l]),mn[x]=min(mn[x],mn[l]);
        if(r) mx[x]=max(mx[x],mx[r]),mn[x]=min(mn[x],mn[r]);
    }
    int build(int*a,int l,int r)
    {
        if(l>r)return 0;
        int mid=l+r>>1;s[mid]=a[mid];
        c[mid][0]=build(a,l,mid-1);fa[c[mid][0]]=mid;
        c[mid][1]=build(a,mid+1,r);fa[c[mid][1]]=mid;
        update(mid);
        return mid;
    }
    void rotate(int x,int&k)
    {
        int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
        if(y==k) k=x; else c[z][c[z][1]==y]=x;
        fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
        c[y][l]=c[x][r];c[x][r]=y;
        update(y);update(x);
    }
    void splay(int x,int&k)
    {
        for(;x!=k;rotate(x,k))
            if(fa[x]!=k) rotate(c[fa[fa[x]]][1]==fa[x]^c[fa[x]][1]==x?x:fa[x],k);
    }
    int Find(int x,int rk)
    {
        int Sz=size[c[x][0]]+1;
        if(Sz==rk) return x;
        if(Sz>rk) return Find(c[x][0],rk);
        else return Find(c[x][1],rk-Sz);
    }
    int Split(int l,int r)
    {
        splay(Find(rt,l),rt);
        splay(Find(rt,r),c[rt][1]);
        return c[c[rt][1]][0];
    }
    void Modify(int x,int rk,int v)
    {
        int Sz=size[c[x][0]]+1;
        if(Sz==rk){s[x]=v;update(x);return;}
        else if(Sz<rk) Modify(c[x][1],rk-Sz,v);
        else Modify(c[x][0],rk,v);
        update(x);
    }
    void ins(int&x,int rk,int v,int last)
    {
        if(!x){x=++cnt;s[x]=mx[x]=mn[x]=v;size[x]=v;fa[x]=last;return;}
        int Sz=size[c[x][0]]+1;
        if(Sz<=rk) ins(c[x][1],rk-Sz,v,x);
        else ins(c[x][0],rk,v,x);
        update(x);
    }
}s,S;
char op[10];
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i) a[i+1]=read(),b[i]=abs(a[i+1]-a[i]);
    s.rt=s.build(a,1,n+2);S.rt=S.build(b,1,n+1);
    s.cnt=n+2;S.cnt=n+1;
    for(int i=1;i<=m;++i)
    {
        scanf("%s",op+1);int x=read(),y=read();
        if(op[2]=='e')
        {
            int z=s.Split(x,x+3);S.Split(x,x+2);
            S.c[S.c[S.rt][1]][0]=s.c[z][0]=s.c[z][1]=0;
            S.s[S.rt]=abs(y-s.s[s.rt]);S.s[S.c[S.rt][1]]=abs(s.s[s.c[s.rt][1]]-y);
            S.update(S.c[S.rt][1]);S.update(S.rt);
            s.s[z]=y;s.update(z);s.update(s.c[s.rt][1]);s.update(s.rt);
        }
        if(op[2]=='n')
        {
            int b=s.Find(s.rt,x+1),a=s.Find(s.rt,x+2);
            s.ins(s.rt,x+1,y,0);s.splay(s.cnt,s.rt);
            S.Modify(S.rt,x+1,abs(y-s.s[b]));
            S.ins(S.rt,x+1,abs(s.s[a]-y),0);S.splay(S.cnt,S.rt);
        }
        if(op[2]=='a')
        {
            int X=s.Split(x,y+2);
            printf("%d\n",s.mx[X]-s.mn[X]);
        }
        if(op[2]=='i')
        {
            int X=S.Split(x,y+1);
            printf("%d\n",S.mn[X]);
        }
    }
    return 0;
}
posted @ 2017-07-17 14:12  FallDream  阅读(238)  评论(0编辑  收藏  举报