【JSOI2007】动态最值 Splay

题目描述

    有一个包含n个元素的数组,要求实现以下操作:
  DELETE k :删除位置k上的数。右边的数往左移一个位置。
  QUERY i j :查询位置i~j上所有数的最小值和最大值。
  例如有10个元素:
这里写图片描述
  QUERY 2 8的结果为2 9。依次执行DELETE 3和DELETE 6(注意这时删除的是原始数组的元素7)后数组变为:
  这里写图片描述
  QUERY 2 8的结果为1 7。

题目大意

删数,求区间最大最小值。

数据范围

1≤n, m≤10^6 数字绝对值小于10^9

样例输入

10 4
1 5 2 6 7 4 9 3 1 5
2 2 8
1 3
1 6
2 2 8

样例输出

2 9
1 7

解题思路

Splay

代码

注意常数巨大,scanf都会超时一组。

#include <bits/stdc++.h>
#define Maxn 1000005
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int a[Maxn],n;
struct splay{
    int f[Maxn],son[Maxn][2],size[Maxn],vl[Maxn],Max[Maxn],Min[Maxn],root;
    void PushUp(int x){
        if(!x)return;
        size[x]=size[son[x][0]]+size[son[x][1]]+1;
        Max[x]=max(max(Max[son[x][0]],Max[son[x][1]]),(x==1||x==n+2?-1<<30:vl[x]));
        Min[x]=min(min(Min[son[x][0]],Min[son[x][1]]),(x==1||x==n+2?1<<30:vl[x]));
    }
    void Rotate(int x){
        int fa=f[x],gr=f[fa],s=son[fa][1]==x,sn=son[x][!s];
        son[f[x]=gr][son[gr][1]==fa]=x;
        son[f[sn]=fa][s]=sn;
        son[f[fa]=x][!s]=fa;
        PushUp(sn);
        PushUp(fa);
        PushUp(x);
    }
    void Splay(int x,int goal){
        if(x==goal)return;
        while(f[x]!=goal){
            if(f[f[x]]!=goal&&(son[f[f[x]]][1]==f[x])==(son[f[x]][1]==x))Rotate(f[x]);
            Rotate(x);
        }
        if(!goal)root=x;
    }
    int Select(int pos){
        if(!pos)return 0;
        int p=root;
        while(size[son[p][0]]+1!=pos){
            if(pos<=size[son[p][0]])p=son[p][0];
            else pos-=size[son[p][0]]+1,p=son[p][1];
        }
        return p;
    }
    void Delete(int pos){
        int u=Select(pos),v=Select(pos+2);
        Splay(u,0);
        Splay(v,u);
        size[son[v][0]]=0;
        f[son[v][0]]=0;
        son[v][0]=0;
        PushUp(v);
        PushUp(u);
    }
    void Build(int L,int r,int fa){
        if(L>r)return;
        int mid=(L+r)/2;
        if(L==r){
            Min[mid]=Max[mid]=vl[mid]=a[mid-1];
            size[mid]=1;
        }else Build(L,mid-1,mid),Build(mid+1,r,mid);
        vl[mid]=a[mid-1];
        f[mid]=fa;
        PushUp(mid);
        son[fa][mid>=fa]=mid;
    }
    void Solve(int L,int r){
        int u=Select(L),v=Select(r+2);
        Splay(u,0);
        Splay(v,u);
        cout<<Min[son[v][0]]<<" "<<Max[son[v][0]]<<"\n";
    }
    void Init(int n){
        Min[n+1]=Min[0]=1<<30;
        Max[n+1]=Max[0]=-1<<30;
        Build(1,n+2,0);
        root=n+3>>1;
    }
}Solver;
int main(){
    n=Getint();
    int m=Getint();
    for(int i=1;i<=n;i++)a[i]=Getint();
    Solver.Init(n);
    while(m--){
        int op=Getint();
        if(op==1)Solver.Delete(Getint());
        else{
            int L=Getint(),r=Getint();
            Solver.Solve(L,r);
        }
    }
    return 0;
}

附我们学校OJ里超时的result
这里写图片描述

转载于:https://www.cnblogs.com/Cedric341561/p/6811009.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值