【块状链表】【SCOI2006】动态最值

题目描述

有一个包含 n 个元素的数组,要求实现以下操作:
DELETE k:删除位置 k 上的数。右边的数往左移一个位置。
QUERY i j :查询位置i~ j 上所有数的最小值和最大值。
例如有 10 个元素:

位置12345678910
元素1526749315

QUERY 2 8的结果为2 9。依次执行DELETE 3和DELETE 6(注意这时删除的是原始数组的元素7)后数组变为:

位置12345678
元素15674315

QUERY 2 8的结果为 1 7。

输入

第一行包含两个数n, m ,表示原始数组的元素个数和操作的个数。
第二行包括n个数,表示原始数组。以下 m 行,每行格式为 1 k或者 2 i j,其中第一个数为1表示删除操作,为2表示询问操作。

输出

对每个询问操作输出一行,包括两个数,表示该范围内的最小值和最大值。

样例输入

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

数据范围

50%的数据满足 1n,m104 ,删除操作不超过 100
100%的数据满足 1n,m106,1m106
对于所有的数据,数组中的元素绝对值均不超过 109


这里给出一个A不了的方法。
测试的时候看到这题于是一时兴起写了个块状链表,以前没写过也没看过所以很垃圾测试全WA调试一下能和答案输出一样十分excited于是写了这个垃圾的题解
思路就是块状链表往里套。
然而块状链表时间代价最低为 O((n)) ,所以总时间代价为 O((n)m)=O(109) ,尽管时限5s,还是过不了。
正解是带删除操作的线段树,这里贴一个同学写的peter_819
上代码【貌似跟网上的都不一样,我自创的好像是反的】

#include <iostream>
#include <cstdio>
using namespace std;
const int inf=~(1<<31), rinf=1<<31;
inline int mIn(int a, int b){return a<b?a:b;}
inline int mAx(int a, int b){return a>b?a:b;}
//链表节点
struct node{
    int val;
    node *fore, *next;
    node(){}
    node(int v):val(v){fore=next=NULL;}
};
//链表块
struct li{
    //区块最值
    int Min, Max;
    node *pre, *last;
    li():Min(inf), Max(rinf){pre=last=NULL;}
    void push(int v){
        if(pre){
            last->next=new node(v);
            last->next->fore=last;
            last=last->next;
        }
        else pre=last=new node(v);
    }
    //暴力更新
    void update(){
        Min=inf, Max=rinf;
        for(node *t=pre;t;t=t->next){
            Min=mIn(t->val, Min);
            Max=mAx(t->val, Max);
        }
    }
    //渣渣的删除,最值被删除只能更新【估计是这里很慢】
    //还没想好解决办法
    void del(node *t){
        if(t==pre)
            if(pre==last){
                pre=last=NULL;
                Min=inf; Max=rinf;
            }
            else{
                pre=pre->next;
                pre->fore=NULL;
                if(t->val==Min||t->val==Max)
                    update();
            }
        else if(t==last)
            if(pre==last)
                pre=last=NULL;
            else{
                last=last->fore;
                last->next=NULL;
                if(t->val==Min||t->val==Max)
                    update();
            }
        else{
            t->fore->next=t->next;
            t->next->fore=t->fore;
            if(t->val==Min||t->val==Max)
                update();
        }
    }
}gg[1000];
int t, n, m, arr[1000000], suf[1001];
/*__attribute__((__optimize__("-O3")))*/ int main(){
    scanf("%d%d", &n, &m);
    for(int i=0;i<n;i++)
        scanf("%d", &arr[i]);
    //分块数
    for(t=0;t*t<n;t++) ;
    for(int i=0;i<t;i++){
        suf[i]=i*t;
        for(int j=0;j<t;j++){
            if(i*t+j>=n)
                break;
            gg[i].push(arr[i*t+j]);
        }
        gg[i].update();
    }
    //防越界
    suf[t]=1000000;
    int a, b, c;
    for(int i=0;i<m;i++){
        scanf("%d", &a);
        if(a==1){
            scanf("%d", &b);
            b--;
            int w, y; node *o;
            //找点
            for(w=0;suf[w+1]<=b;w++) ;
            o=gg[w].pre;
            for(y=0;suf[w]+y<b;y++) o=o->next;
            gg[w].del(o);
            //链表块被删光了
            if(!gg[w].pre){
                gg[w].Min=inf;
                gg[w].Max=rinf;
            }
            for(w=w+1;w<t;w++)
                suf[w]--;
        }
        else{
            scanf("%d%d", &b, &c);
            b--, c--;
            int w1, w2, y, MIN=inf, MAX=rinf;
            for(w1=0;suf[w1+1]<=b;w1++) ;
            for(w2=w1;suf[w2+1]<=c;w2++) ;
            node *o1=gg[w1].pre, *o2=gg[w2].pre;
            for(y=0;suf[w1]+y<b;y++) o1=o1->next;
            //同一链表块,测试就错这里了
            if(w1==w2){
                for(;suf[w2]+y<=c;y++){
                    MIN=mIn(MIN, o1->val);
                    MAX=mAx(MAX, o1->val);
                    o1=o1->next;
                }
            }
            //跨链表块
            else{
                for(;o1;o1=o1->next){
                    MIN=mIn(MIN, o1->val);
                    MAX=mAx(MAX, o1->val);
                }
                for(y=w1+1;y<w2;y++){
                    MIN=mIn(MIN, gg[y].Min);
                    MAX=mAx(MAX, gg[y].Max);
                }
                for(y=0;suf[w2]+y<=c;y++){
                    MIN=mIn(MIN, o2->val);
                    MAX=mAx(MAX, o2->val);
                    o2=o2->next;
                }
            }
            printf("%d %d\n", MIN, MAX);
        }
    }
    return 0;
}

块状链表写好了能快一点?反正我自己编的可能有冗余或者常数问题。


附:
正在测试 minmax.0(minmax.0.in)… 正确 0.002秒
正在测试 minmax.1(minmax.1.in)… 正确 0.002秒
正在测试 minmax.2(minmax.2.in)… 正确 0.020秒
正在测试 minmax.3(minmax.3.in)… 正确 0.013秒
正在测试 minmax.4(minmax.4.in)… 正确 0.028秒
正在测试 minmax.5(minmax.5.in)… 正确 1.759秒
正在测试 minmax.6(minmax.6.in)… 正确 2.603秒
正在测试 minmax.7(minmax.7.in)… 正确 4.169秒
正在测试 minmax.8(minmax.8.in)… 正确 3.780秒
正在测试 minmax.9(minmax.9.in)… 正确 8.359秒

我去掉了注释

正在测试 minmax.0(minmax.0.in)… 正确 0.002秒
正在测试 minmax.1(minmax.1.in)… 正确 0.002秒
正在测试 minmax.2(minmax.2.in)… 正确 0.014秒
正在测试 minmax.3(minmax.3.in)… 正确 0.009秒
正在测试 minmax.4(minmax.4.in)… 正确 0.020秒
正在测试 minmax.5(minmax.5.in)… 正确 0.758秒
正在测试 minmax.6(minmax.6.in)… 正确 1.500秒
正在测试 minmax.7(minmax.7.in)… 正确 2.413秒
正在测试 minmax.8(minmax.8.in)… 正确 2.125秒
正在测试 minmax.9(minmax.9.in)… 正确 4.179秒

爽。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值