【JZOJ 4986】 神秘物质

8 篇文章 0 订阅

Description

这里写图片描述

Analysis

某神奇帝都OI冬令营的题
max x y相当于整个区间的最大减最小
min x y相当于相邻两个数差值最小值
insert,merge什么的splay维护
比赛的时候没时间拍了结果过掉了。。。
听说块链也可以过。。。也是裸的
为什么OI比赛中要出板题==

Code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=200005,INF=2147483640/2;
int n,tot,root,f[N],size[N],key[N],a[N][2],mx[N],mn[N],le[N],ri[N],cmn[N];
int pd(int x)
{
    return x==a[f[x]][1];
}
int update(int x)
{
    int ls=a[x][0],rs=a[x][1];
    size[x]=1+size[ls]+size[rs];
    mx[x]=mn[x]=key[x];
    if(ls) mx[x]=max(mx[x],mx[ls]),mn[x]=min(mn[x],mn[ls]);
    if(rs) mx[x]=max(mx[x],mx[rs]),mn[x]=min(mn[x],mn[rs]);
    le[x]=le[ls],ri[x]=ri[rs];
    if(!ls) le[x]=key[x];
    if(!rs) ri[x]=key[x];
    cmn[x]=INF;
    if(ls) cmn[x]=min(abs(ri[ls]-key[x]),cmn[ls]);
    if(rs) cmn[x]=min(cmn[x],min(abs(key[x]-le[rs]),cmn[rs]));
}
void rotate(int x)
{
    int y=f[x],z=pd(x);
    a[y][z]=a[x][1-z];
    if(a[x][1-z]) f[a[x][1-z]]=y;
    f[x]=f[y];
    if(f[y]) a[f[y]][pd(y)]=x;
    a[x][1-z]=y,f[y]=x;
    update(y);
}
void splay(int x,int y)
{
    if(!y) root=x;
    while(f[x]!=y)
    {
        if(f[f[x]]!=y)
            if(pd(x)==pd(f[x])) rotate(f[x]);
            else rotate(x);
        rotate(x);
    }
    update(x);
}
int kth(int x,int k)
{
    if(size[a[x][0]]+1==k) return x;
    if(k<=size[a[x][0]]) return kth(a[x][0],k);
    else return kth(a[x][1],k-size[a[x][0]]-1);
}
void insert(int p,int z)
{
    int x=kth(root,p+1),y=kth(root,p+2);
    splay(x,0);splay(y,x);
    a[y][0]=++tot,f[tot]=y,key[tot]=z,cmn[tot]=INF;
    update(tot);update(y);update(x);
}
void del(int p)
{
    int x=kth(root,p),y=kth(root,p+2);
    splay(x,0),splay(y,x);
    a[y][0]=0;
    update(y);update(x);
}
void merge(int p,int z)
{
    del(p);del(p);
    insert(p-1,z);
}
int qmin(int l,int r)
{
    int x=kth(root,l),y=kth(root,r+2);
    splay(x,0),splay(y,x);
    return cmn[a[y][0]];
}
int qmax(int l,int r)
{
    int x=kth(root,l),y=kth(root,r+2);
    splay(x,0),splay(y,x);
    return mx[a[y][0]]-mn[a[y][0]];
}
int main()
{
    char ch;
    int x,y,_;
    scanf("%d %d",&n,&_);
    key[1]=cmn[1]=INF;
    fo(i,2,n+1)
    {
        scanf("%d",&key[i]);cmn[i]=INF;
        f[i]=i-1,a[i-1][1]=i;
        update(i);
    }
    f[n+2]=n+1,a[n+1][1]=n+2,key[n+2]=cmn[n+2]=INF;
    splay(n+2,0);
    tot=n+2;
    scanf("\n");
    while(_--)
    {
        scanf("%c",&ch);
        if(ch=='m')
        {
            scanf("%c",&ch);
            if(ch=='e')
            {
                scanf("rge %d %d\n",&x,&y);
                merge(x,y);
            }
            if(ch=='i')
            {
                scanf("n %d %d\n",&x,&y);
                printf("%d\n",qmin(x,y));
            }
            if(ch=='a')
            {
                scanf("x %d %d\n",&x,&y);
                printf("%d\n",qmax(x,y));
            }
        }
        else
        {
            scanf("nsert %d %d\n",&x,&y);
            insert(x,y);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值