bzoj4864 [BeiJing 2017 Wc]神秘物质

本文介绍了一种使用伸展树(splay tree)处理区间合并、插入及查询区间极差最大值与最小值的问题解决方法。该算法适用于动态数据集,能够高效地进行区间更新和查询。文中提供了一个具体的实现示例。

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

Description


要求资瓷以下操作

merge x e 合并第x个元素和第x+1个元素,权值变为e
insert x e 在第x个元素和第x+1个元素之间插入一个权值为 e 的新元素。
max x y 当前第 x 到第 y 个元素之间的任意子区间中区间极差的最大值;
min x y 当前第 x 到第 y 个元素子之间的任意子区间中区间极差的最小值。

N<=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。

Solution


动态删除和添加就不能用线段树惹

max询问实质就是找到区间中最大值和最小值的差
min询问实质就是找到区间中相邻元素权值差值的最小值
那么splay维护区间最大值、最小值、相邻差值的最小值即可

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int INF=0x3f3f3f3f;
const int N=400005;

struct treeNode {int son[2],fa,size,e,max,min,rec,delta;} t[N];

int e[N],root,tot;

void new_node(int fa,int e,int delta) {
    t[++tot]=(treeNode) {{0,0},fa,1,e,e,e,delta,delta};
    if (e==INF) {
        t[tot].max=-INF;
        t[tot].e=0;
        t[tot].rec=INF;
    }
}

void push_up(int x) {
    t[x].max=std:: max(t[t[x].son[0]].max,t[t[x].son[1]].max);
    t[x].min=std:: min(t[t[x].son[0]].min,t[t[x].son[1]].min);
    if (t[x].e) {
        t[x].max=std:: max(t[x].max,t[x].e);
        t[x].min=std:: min(t[x].min,t[x].e);
    }
    t[x].rec=std:: min(abs(t[x].delta),std:: min(t[t[x].son[0]].rec,t[t[x].son[1]].rec));
    t[x].size=t[t[x].son[0]].size+t[t[x].son[1]].size+1;
}

void rotate(int x) {
    int y=t[x].fa; int z=t[y].fa;
    int k=t[y].son[1]==x;
    t[z].son[t[z].son[1]==y]=x; t[x].fa=z;
    t[y].son[k]=t[x].son[!k]; t[t[x].son[!k]].fa=y;
    t[y].fa=x; t[x].son[!k]=y;
    push_up(y); push_up(x);
}

void splay(int x,int goal=0) {
    while (t[x].fa!=goal) {
        int y=t[x].fa; int z=t[y].fa;
        if (z!=goal) {
            if ((t[z].son[1]==y)^(t[y].son[1]==x)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
    if (!goal) root=x;
}

int kth(int k) {
    int x=root;
    while (233) {
        if (t[t[x].son[0]].size+1==k) return x;
        if (t[t[x].son[0]].size>=k) {
            x=t[x].son[0];
        } else {
            k-=t[t[x].son[0]].size+1;
            x=t[x].son[1];
        }
    }
}

int main(void) {
    freopen("data.in","r",stdin);
    freopen("myp.out","w",stdout);
    t[0].max=-INF; t[0].min=t[0].rec=INF;
    int n,m; scanf("%d%d",&n,&m);
    rep(i,1,n) scanf("%d",&e[i]);
    new_node(0,0,0); t[tot].max=-INF; t[tot].min=t[tot].rec=t[tot].delta=INF; root=1;
    rep(i,1,n) {
        int tx=kth(i);
        splay(tx);
        new_node(root,e[i],e[i]-e[i-1]);
        t[root].son[1]=tot;
        splay(tot);
    }
    splay(kth(n+1));
    new_node(root,0,0); t[root].son[1]=tot;
    t[tot].max=-INF; t[tot].min=INF;
    while (m--) {
        char opt[8]; scanf("%s",opt);
        int x,y; scanf("%d%d",&x,&y);
        if (opt[1]=='e') {
            int tx=kth(x+1); splay(tx);
            int ty=kth(x+3); splay(ty,tx);
            t[tx].delta+=y-t[tx].e;
            t[tx].e=y;
            t[ty].delta=t[ty].e-t[tx].e;
            t[ty].son[0]=0;
            push_up(ty); push_up(tx);
        } else if (opt[0]=='i') {
            int tx=kth(x+1); splay(tx);
            int ty=kth(x+2); splay(ty,tx);
            new_node(ty,y,y-t[tx].e);
            t[ty].son[0]=tot;
            t[ty].delta=t[ty].e-t[tot].e;
            push_up(ty); push_up(tx);
            splay(tot);
        } else if (opt[1]=='a') {
            int tx=kth(x); splay(tx);
            int ty=kth(y+2); splay(ty,tx);
            printf("%d\n", t[t[ty].son[0]].max-t[t[ty].son[0]].min);
        } else {
            int tx=kth(x+1); splay(tx);
            int ty=kth(y+2); splay(ty,tx);
            printf("%d\n", t[t[ty].son[0]].rec);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值