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

题目描述

传送门

题目大意:给出一个长度为n的序列
merge x e 将x,x+1合并,得到e
insert x e 在x,x+1之间插入 e
max x y 当前[x,y]中任意子区间中区间极差的最大值
min x y 当前[x,y]中任意子区间中区间极差的最小值

题解

这道题只要想清楚了min操作就是一个splay的裸题。
min中有贡献的子区间的长度只能是2,所以我们只要考虑相邻的两个数就可以了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200003
#define inf 2000000000
using namespace std;
int val[N],mx[N],mn[N],ck[N],gv[N],ch[N][2],fa[N],size[N],cnt,root;
int n,m,a[N];
void update(int now)
{
    int l=ch[now][0]; int r=ch[now][1];
    mx[now]=mn[now]=val[now]; ck[now]=gv[now]; size[now]=1;
    if (l) mx[now]=max(mx[now],mx[l]),mn[now]=min(mn[now],mn[l]),
           ck[now]=min(ck[now],ck[l]),size[now]+=size[l];
    if (r) mx[now]=max(mx[now],mx[r]),mn[now]=min(mn[now],mn[r]),
           ck[now]=min(ck[now],ck[r]),size[now]+=size[r];
}
void clear(int x)
{
    val[x]=mx[x]=mn[x]=ck[x]=gv[x]=ch[x][0]=ch[x][1]=0;
}
int build(int l,int r)
{
    if (l>r) return 0;
    if (l==r) {
        int now=++cnt;
        val[now]=mx[now]=mn[now]=a[l]; size[now]=1;
        ck[now]=gv[now]=abs(a[l]-a[l-1]);
        return now;
    }
    int mid=(l+r)/2; int now=++cnt;
    val[now]=a[mid]; gv[now]=abs(a[mid]-a[mid-1]);
    ch[now][0]=build(l,mid-1);
    ch[now][1]=build(mid+1,r);
    fa[ch[now][0]]=fa[ch[now][1]]=now;
    update(now);
    return now;
}
int get(int x)
{
    return ch[fa[x]][1]==x;
}
void rotate(int x)
{
    int y=fa[x]; int z=fa[y]; int which=get(x);
    ch[y][which]=ch[x][which^1]; fa[ch[x][which^1]]=y;
    if (z) ch[z][ch[z][1]==y]=x;
    fa[x]=z; ch[x][which^1]=y; fa[y]=x;
    update(y); update(x);
}
void splay(int x,int tar)
{
    for (int f;(f=fa[x])!=tar;rotate(x)) 
     if (fa[f]!=tar)
      rotate(get(x)==get(f)?f:x);
    if (!tar) root=x;
}
int find(int x)
{
    int now=root; 
    while (true) {
        if (size[ch[now][0]]>=x) 
         now=ch[now][0];
        else {
            x-=size[ch[now][0]];
            if (x==1) return now;
            x--; now=ch[now][1];
        }
    }
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("my.out","w",stdout);
    scanf("%d%d",&n,&m);
    a[1]=a[n+2]=inf;
    for (int i=1;i<=n;i++) scanf("%d",&a[i+1]);
    root=build(1,n+2);
    for (int i=1;i<=m;i++) {
        char s[10]; int x,y; scanf("%s%d%d",s+1,&x,&y);
        if (s[2]=='e') {
            int aa=find(x); int bb=find(x+3);
            splay(aa,0); splay(bb,aa);
            int t=ch[ch[root][1]][0];
            clear(t);
            val[t]=mx[t]=mn[t]=y; size[t]=1;
            ck[t]=gv[t]=abs(val[root]-val[t]);
            gv[ch[root][1]]=abs(val[ch[root][1]]-val[t]);
            update(ch[root][1]); update(root);
        }  
        if (s[2]=='i')  {
            int aa=find(x+1); int bb=find(y+2);
            splay(aa,0); splay(bb,aa);
            int t=ch[ch[root][1]][0];
            printf("%d\n",ck[t]);
        }
        if (s[2]=='a') {
            int aa=find(x); int bb=find(y+2);
            splay(aa,0); splay(bb,aa);
            int t=ch[ch[root][1]][0];
            printf("%d\n",mx[t]-mn[t]);
        }
        if (s[1]=='i') {
            int aa=find(x+1); int bb=find(x+2);
            splay(aa,0); splay(bb,aa);
            int t=++cnt; fa[t]=ch[root][1]; ch[ch[root][1]][0]=cnt;
            val[t]=mx[t]=mn[t]=y; size[t]=1;
            ck[t]=gv[t]=abs(val[root]-val[t]);
            gv[ch[root][1]]=abs(val[ch[root][1]]-val[t]);
            update(ch[root][1]); update(root);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值