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

Description
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 的子区间。
小诚坚信这项研究可以获得诺贝尔物理学奖。为了让小诚早日了结心愿,你能否帮助他实现上述的观测和测量呢?
Input

第一行, 两个整数 N, M, 分别表示最初的原子数目和事件总数。
第二行, N 个整数 E1, E2, …, EN, 由空格隔开。依次表示每个原子的能量。
接下来 M 行, 每行为一个字符串和两个整数, 描述一次事件,格式见题目描述。
N&lt;=100,000,M&lt;=100,000N&lt;=100,000,M&lt;=100,000N<=100,000,M<=100,000
1 ≤ e, Ei ≤ 109。 设 N’ 为当前时刻原子数目。
对于 merge 类事件, 1 ≤ x ≤ N’-1;
对于 insert 类事件, 1 ≤ x ≤ N’;
对于 max 和 min 类事件, 1 ≤ x < y ≤ N’。
任何时刻,保证 N’ ≥ 2。
Output

输出若干行, 按顺序依次表示每次 max 和 min 类事件的测量结果。
Sample Input
4 3
5 8 10 2
max 1 3
min 1 3
max 2 4

Sample Output
5
2
8

分析:
子区间的最大极差就是整个区间的极差,最小极差是两两相邻的数的差的最小值。
因为有删除和插入,考虑splay。
splay维护相当于区间合并,对于一个区间(子树),维护lnumlnumlnumrnumrnumrnumansansansminminminmaxmaxmax,分别表示区间左端点的值,右端点的值,最小极差,区间最小值,区间最大值。合并很显然。

代码:

/**************************************************************
    Problem: 4864
    User: ypxrain
    Language: C++
    Result: Accepted
    Time:3932 ms
    Memory:16920 kb
****************************************************************/
 
#include <iostream>
#include <cstdio>
#include <cmath>
 
const int maxn=1e5+7;
const int inf=0x3f3f3f3f;
 
using namespace std;
 
int n,m,x,y,root,cnt,num;
char op[20];
 
struct rec{
    int minn,maxx,ans,lnum,rnum;
};
 
struct node{
    int l,r,x,fa,size;
    rec data;
}t[maxn*4];
 
rec merge(rec a,rec b)
{
    rec c;
    c.lnum=a.lnum;
    c.rnum=b.rnum;
    c.minn=min(a.minn,b.minn);
    c.maxx=max(a.maxx,b.maxx);
    int d=a.rnum-b.lnum;
    if (d<0) d=-d;
    c.ans=min(min(a.ans,b.ans),d);
    return c;
}
 
rec neww(int x)
{
    return (rec){x,x,inf,x,x};
}
 
void updata(int x)
{
    t[x].size=t[t[x].l].size+t[t[x].r].size+1;
    if (t[x].l) t[x].data=merge(t[t[x].l].data,neww(t[x].x));
           else t[x].data=neww(t[x].x);
    if (t[x].r) t[x].data=merge(t[x].data,t[t[x].r].data);
}
 
void rttr(int x)
{
    int y=t[x].l;
    t[x].l=t[y].r;
    if (t[y].r) t[t[y].r].fa=x;
    if (t[t[x].fa].l==x) t[t[x].fa].l=y;
    else if (t[t[x].fa].r==x) 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;
    t[x].r=t[y].l;
    if (t[y].l) t[t[y].l].fa=x;
    if (t[t[x].fa].l==x) t[t[x].fa].l=y;
    else if (t[t[x].fa].r==x) t[t[x].fa].r=y;
    t[y].fa=t[x].fa;
    t[x].fa=y;
    t[y].l=x;
    updata(x); updata(y);
}
 
bool isroot(int x)
{
    return t[x].fa==0;
}
 
void splay(int x)
{
    while (!isroot(x))
    {
        int p=t[x].fa,g=t[p].fa;
        if (isroot(p))
        {
            if (t[p].l==x) rttr(p);
                      else rttl(p);
        }
        else
        {
            if (t[p].l==x)
            {
                if (t[g].l==p) rttr(p),rttr(g);
                          else rttr(p),rttl(g);
            }
            else
            {
                if (t[g].l==p) rttl(p),rttr(g);
                          else rttl(p),rttl(g);
            }
        }
    }
    root=x;
}
 
int find(int x,int k)
{
   // if ((!k) || (t[x].size<k)) return 0;
    int size=t[t[x].l].size;
    if (size==k-1) return x;
    if (k<=size) return find(t[x].l,k);
            else return find(t[x].r,k-size-1);
}
 
void del(int x,int k)
{
    int a=find(root,x);
    if (x<num-1)
    {
        int b=find(root,x+2);
        splay(b),splay(a);
        t[a].x=k;
        t[b].l=0;
        updata(b),updata(a);
    }
    else
    {
        splay(a);
        t[a].x=k;
        t[a].r=0;
        updata(a);
    }
    num--;
}
 
void ins(int x,int k)
{
    int a=find(root,x);
    if (x<num)
    {
        int b=find(root,x+1);
        splay(b),splay(a);
        t[b].l=++cnt;
        t[cnt].x=k;
        t[cnt].fa=b;
        t[cnt].data=neww(k);
        t[cnt].size=1;  
        updata(b),updata(a);
    }
    else
    {
        splay(a);
        t[a].r=++cnt;
        t[cnt].x=k;
        t[cnt].fa=a;
        t[cnt].data=neww(k);
        t[cnt].size=1;
        updata(a);
    }
    num++;
}
 
int getans(int x,int y,int op)
{
    if (x==1)
    {
        if (y==num)
        {
            if (op==1) return t[root].data.maxx-t[root].data.minn;
                  else return t[root].data.ans;
        }
        else
        {
            int b=find(root,y+1);
            splay(b);
            if (op==1) return t[t[b].l].data.maxx-t[t[b].l].data.minn;
                  else return t[t[b].l].data.ans;
        }
    }
    else
    {
        if (y==num)
        {
            int b=find(root,x-1);
            splay(b);
            if (op==1) return t[t[b].r].data.maxx-t[t[b].r].data.minn;
                  else return t[t[b].r].data.ans;
        }
        else
        {
            int a=find(root,x-1),b=find(root,y+1);
            splay(b),splay(a);
            if (op==1) return t[t[b].l].data.maxx-t[t[b].l].data.minn;
                  else return t[t[b].l].data.ans;
        }
    }
}
 
int main()
{
    scanf("%d%d",&n,&m);    
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        t[i].x=x;
        t[i].l=i-1;
        t[i-1].fa=i;
        t[i].size=i;
        if (i>1) t[i].data=merge(t[t[i].l].data,neww(x));
            else t[i].data=neww(x);
    }   
    root=n;
    cnt=num=n;
    for (int i=1;i<=m;i++)
    {       
        scanf("%s%d%d",op,&x,&y);
        if (op[1]=='e') del(x,y);
        if (op[1]=='n') ins(x,y);
        if (op[1]=='a') printf("%d\n",getans(x,y,1));
        if (op[1]=='i') printf("%d\n",getans(x,y,0));
    }
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值