P7549 [BJWC2017] 神秘物质

P7549 [BJWC2017] 神秘物质

题目背景

21ZZ 年,冬。

小诚退休以后,不知为何重新燃起了对物理学的兴趣。他从研究所借了些实验仪器,整天研究各种微观粒子。

题目描述

这一天,小诚刚从研究所得到了一块奇异的陨石样本,便迫不及待地开始观测。在精密仪器的视野下,构成陨石的每个原子都无比清晰。

小诚发现,这些原子排成若干列,每一列的结构具有高度相似性。于是,他决定对单独一列原子进行测量和测试。

被选中的这列共有 \(N\) 个顺序排列的原子。最初, 第 \(i\) 个原子具有能量 \(E_i\)。 随着时间推移和人为测试,这列原子在观测上会产生两种变化:

  • 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\),分别表示最初的原子数目和事件总数。

第二行包含 \(N\) 个以空格分隔的整数 \(E_1,E_2,...,E_N\),依次表示每个原子的能量。

接下来 \(M\) 行,每行为一个字符串和两个整数,描述一次事件,格式见题目描述。

输出格式

输出若干行,按顺序依次表示每次 max 和 min 类事件的测量结果。

对于 \(100\%\) 的数据,\(1 \le N \le 10^5\)\(1 \le M \le 10^5\)\(1 \le e,E_i \le 10^9\)

\(N'\) 为当前时刻原子数目:

  • 对于 merge 类事件,\(1 \le x \le N' - 1\)
  • 对于 insert 类事件,\(1 \le x \le N'\)
  • 对于 max 和 min 类事件,\(1 \le x < y \le N'\)

任何时刻,保证 \(N' \ge 2\)

Solution:

看到题目:这不妥妥平衡树?
看完题目:区间?查询?平衡树?
算了我还是开摆吧

我们先来讨论一下那两个我们在平衡树中并不熟悉的操作:首先,对于区间极差的最大值,那么显然就是区间中的最大值与最小值的差,这部分没什么可改的,直接在平衡树的每一个节点维护一个该节的子树中的最大最小值就好了

我们再来看一下这个无比诡异的区间极差最小值:
对于两个数的区间{a,b} 他们的极差是\(\max{(a,b)}-\min{(a,b)}\)
而对于{a,b,c}:
他们的极差是\(\max{(a,b,c)}-\min{(a,b,c)}\)
显然:
\(\max{(a,b,c)}\ge \max{(a,b)}\)
\(-\min{(a,b,c)}\ge -\min{(a,b)}\)
二式相加 :
\(\max{(a,b,c)}-\min{(a,b,c)}\ge \max{(a,b)}-\min{(a,b)}\)
\(delta_{a,b,c}\ge delta_{a,b}\)
所以说在区间的极差是单调不减的,所以我们要求的极差最小值一定是相邻两个数的差的最小值

我们考虑在平衡树的节点维护两个东西pre和suf用间接来表示当前节点(在线性数组中)前一个元素的权值以及后一个元素的权值。
在平衡树上描述就是:pre是当前节点的子树下最靠左的那一个节点的值,suf就是当前节点子树下最靠右的那个节点的值,那么显然,假设当前元素在线性数组中的是a[i]:

那么a[i-1]=t[ls].suf,a[i+1]=t[rs].pre

然后再注意一下本题的边界讨论这题就可以愉快的AC了

Code:

#include <bits/stdc++.h>
#define int long long
const int N=3e5+5;
const int inf=1e9;
using namespace std;
int n,m,rt,tot;
//FHQ_Treap
struct Tree{
    int ls,rs,mi,ma,val,rad,pre,suf,d,siz;
}t[N<<2];
void push_up(int x)
{
    int ls=t[x].ls,rs=t[x].rs;
    t[x].siz=t[ls].siz+t[rs].siz+1;
    t[x].ma=t[x].mi=t[x].pre=t[x].suf=t[x].val;
    t[x].d=inf;
    if(ls)
    {
        t[x].mi=min(t[x].mi,t[ls].mi);
        t[x].ma=max(t[x].ma,t[ls].ma);
        t[x].pre=t[ls].pre;
        t[x].d=min(t[x].d,min(t[ls].d,abs(t[x].val-t[ls].suf)));
    }
    if(rs)
    {
        t[x].mi=min(t[x].mi,t[rs].mi);
        t[x].ma=max(t[x].ma,t[rs].ma);
        t[x].suf=t[rs].suf;
        t[x].d=min(t[x].d,min(t[rs].d,abs(t[x].val-t[rs].pre)));
    }
}
void split(int now,int k,int &x,int &y)
{
    if(!now)
    {
        x=y=0;
        return ;
    }
    int ls=t[now].ls,rs=t[now].rs;
    if(t[ls].siz+1<=k)
    {
        x=now;
        split(t[now].rs,k-(t[ls].siz+1),t[now].rs,y);
    }
    else
    {
        y=now;
        split(t[now].ls,k,x,t[now].ls);
    }
    push_up(now);
}
int merge(int x,int y)
{
    if(!x||!y)return x+y;
    if(t[x].rad<t[y].rad)
    {
        t[x].rs=merge(t[x].rs,y);
        push_up(x);
        return x;
    }
    else
    {
        t[y].ls=merge(x,t[y].ls);
        push_up(y);
        return y;
    }
}
int add(int k)
{
    t[++tot].rad=rand();
    t[tot].val=t[tot].mi=t[tot].ma=t[tot].pre=t[tot].suf=k;
    t[tot].siz=1;
    t[tot].d=inf;
    return tot;
}
void insert(int pos,int x)
{
    int l,r;
    split(rt,pos,l,r);
    rt=merge(merge(l,add(x)),r);
}
void Merge(int pos,int k)
{
    int x,y,z;
    split(rt,pos+1,x,y);
    split(x,pos-1,x,z);
    rt=merge(merge(x,add(k)),y);
}
int query_ma(int l,int r)
{
    int x,y,z,ans;
    split(rt,r,y,x);split(y,l-1,z,y);
    ans=t[y].ma-t[y].mi;
    rt=merge(merge(z,y),x);
    return ans;
}
int query_mi(int l,int r)
{
    int x,y,z,ans;
    split(rt,r,y,x);
    split(y,l-1,z,y);
    ans=t[y].d;
    rt=merge(merge(z,y),x);
    return ans;
}
char opt[999];
void work()
{
    cin>>n>>m;
    srand(545006);
    t[++tot].val=inf;t[tot].mi=t[tot].d=inf;t[tot].ma=-1;
    for(int i=1,x;i<=n;i++)
    {
        scanf("%lld",&x);
        insert(i-1,x);
    }
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%s",opt);
        scanf("%lld%lld",&x,&y);
        if(opt[1]=='e')
        {
            Merge(x,y);
        }
        if(opt[1]=='n')
        {
            insert(x,y);
        }
        if(opt[1]=='a')
        {
            int ans=query_ma(x,y);
            printf("%lld\n",ans);
        }
        if(opt[1]=='i')
        {
            int ans=query_mi(x,y);
            printf("%lld\n",ans);
        }
    }
}
#undef int
int main()
{
    //freopen("secret.in","r",stdin);
    //freopen("secret.out","w",stdout);
    work();
    return 0;
}
posted @ 2024-12-06 11:58  liuboom  阅读(22)  评论(0)    收藏  举报