[BZOJ1500][NOI2005]维修数列(Splay)

Navicat16/17数据库密码安全解析与实战解密指南 本文详细解析了Navicat 16/17版本中数据库密码的加密机制,并提供了实用的密码找回指南。通过导出连接文件获取加密密文,利用基于AES-128-CBC算法的本地HTML工具,可安全、离线地解密遗忘的密码。文章强调该方法仅适用于合法恢复自有密码,并给出了操作步骤与安全建议。 阅读详情

=== ===

这里放传送门

=== ===

题解

这道题真TM难写啊这就是传说中的Splay板子题?ATP在2016SDSC的某天晚上从晚上9点写到11点码了出来,第二天上午调了一上午各种对拍各种T最后照着题解改了update的姿势才A掉。。。

前几个操作比较简单啦。第一个操作就把读进来的数字用build过程搞成一个Splay然后插进去就可以了。先找到第pos+1个数旋转到根,再找它的后继旋转到根的右儿子。这里有一句要提,ATP以前在Splay里面找前驱后继的方法是先把要找的那个点旋转到根,再找左子树中最靠右的儿子(前驱)和右子树中最靠左的儿子(后继)的,但是这样实际上常数奇大无比因为还带着一个Splay操作。后来ATP看算导的时候发现它在讲红黑树那一章讲了一个不需要Splay的找前驱后继的方法。。以找前驱为例,如果它有左儿子就找左子树最靠右的节点,否则就顺着父亲指针往上跳,设当前节点为v,找到第一个是它父亲右儿子的v,然后返回v的父亲即可。这样做时间复杂度也是树高级别的并且常数小得多。。注意在调用节点的儿子之前先push一下下放标记。(话说是不是只有愚蠢ATP和它愚蠢的小伙伴们用那种愚蠢的找前驱后继的方法= =)

第二个操作只要把那一坨子树揪出来扔到内存池里就行了,这里打了一个del标记,其实也不需要,只要每次从内存池里提取节点的时候看它下面有没有拖着子树,如果有的话先把子树分别塞到内存池里再把它提出来就可以了。三,四,五操作都是经典的平衡树操作,重点是第六个。

处理这一类问题的经典方法就是在节点上维护三个东西:靠着左边的最大值,靠着右边的最大值和全局最大值。这样update的时候就是左子树全局最大、右子树全局最大和左右子树拼起来的那一部分取一个max就可以了。但是在维护靠左最大lMax和靠右最大rMax的时候ATP出问题了。。一开始把这两个东西设定的太严格了,不允许它出现空串,这样的话在update的时候就特别麻烦,要分成各种情况讨论。。但是如果把限制放宽一点,允许这两个东西在序列全为负数的时候记录空串就能大大简化情况,并且能大大缩小update过程的常数,但是注意最后结果是不允许用空串的,所以全局最大值要特判一下。因为update过程调用特别频繁,所以它的常数会对程序整体运行时间造成特别大的影响。。一开始愚蠢的ATP把count过程写了40多行,结果大数据跑了1s+,改了以后大数据0.4s就过了。。。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 1000000000
#define inc(x)(x=(x%600000)+1)
using namespace std;
int n,m,a[500010],head,tail;
struct Node{
    Node *ch[2],*fa;
    int size,sum,dlt,data,lMax,rMax,tMax;
    bool rev,del;
    Node();
    bool pl(){return this==fa->ch[1];}
    void Rever(){swap(ch[0],ch[1]);swap(lMax,rMax);rev^=1;}
    void Cover(int v);
    void count();
    void push();
    Node *Nxt();
    void print();
}*null,*Root,Pool[600010],*q[600010];
Node::Node(){
    ch[1]=ch[0]=fa=null;rev=del=false;
    size=sum=data=lMax=rMax=0;
    dlt=inf;tMax=-inf;
}
void Del(Node *k){inc(tail);q[tail]=k;k->del=true;}
Node *New(Node *f,int d){
    inc(head);
    if (q[head]->ch[0]!=null) Del(q[head]->ch[0]);
    if (q[head]->ch[1]!=null) Del(q[head]->ch[1]);
    *q[head]=Node();
    Node *k=q[head];
    k->fa=f;k->data=k->sum=k->tMax=d;
    k->size=1;
    k->lMax=k->rMax=(d<0)?0:d;
    return k;
}
void Node::Cover(int v){
    sum=v*size;data=dlt=v;
    if (v<0){lMax=rMax=0;tMax=v;}//对lMax和rMax的设定不能太严格
    else lMax=rMax=tMax=v*size;//分成正数和负数两种情况讨论
}
void Node::count(){
    size=ch[0]->size+ch[1]->size+1;
    sum=ch[1]->sum+ch[0]->sum+data;
    lMax=max(ch[0]->lMax,ch[0]->sum+data+ch[1]->lMax);
    rMax=max(ch[1]->rMax,ch[1]->sum+data+ch[0]->rMax);
    tMax=max(ch[0]->tMax,ch[1]->tMax);
    tMax=max(tMax,ch[0]->rMax+data+ch[1]->lMax);
}
void Node::push(){
    if (rev==true){
        if (ch[0]!=null) ch[0]->Rever();
        if (ch[1]!=null) ch[1]->Rever();
        rev=false;
    }
    if (dlt!=inf){
        if (ch[0]!=null) ch[0]->Cover(dlt);
        if (ch[1]!=null) ch[1]->Cover(dlt);
        dlt=inf;
    }
}
Node* Node::Nxt(){
    push();
    if (ch[1]!=null){
        Node *k=ch[1];
        while (k->ch[0]!=null){
            k->push();k=k->ch[0];
        }//注意这里随时push一下
        return k;
    }else{
        Node *k=this;//处理没有右儿子的情况
        while (k->pl()==1){k->count();k=k->fa;}
        return k->fa;
    }
}
void Rotate(Node *k){
    Node *r=k->fa;
    if (r==null||k==null) return;
    int x=k->pl()^1;
    r->push();k->push();
    r->ch[x^1]=k->ch[x];
    if (k->ch[x]!=null)
      r->ch[x^1]->fa=r;
    if (r->fa==null) Root=k;
    else r->fa->ch[r->pl()]=k;
    k->fa=r->fa;r->fa=k;
    k->ch[x]=r;
    r->count();
    k->count();
}
void Splay(Node *r,Node *tar){
    for (;r->fa!=tar;Rotate(r))
      if (r->fa->fa!=tar)
        Rotate(r->pl()==r->fa->pl()?r->fa:r);
}
Node *build(int l,int r){
    if (l>r) return null;
    int mid=(l+r)>>1;
    Node *k=New(null,a[mid]);
    k->ch[0]=build(l,mid-1);
    k->ch[1]=build(mid+1,r);
    if (k->ch[0]!=null) k->ch[0]->fa=k;
    if (k->ch[1]!=null) k->ch[1]->fa=k;
    k->count();return k;
}
void Find(int k,Node *tar){
    Node *r=Root;
    r->push();r->count();
    while (k!=r->ch[0]->size+1){
        if (k<r->ch[0]->size+1) r=r->ch[0];
        else{
            k=k-r->ch[0]->size-1;r=r->ch[1];
        }
        r->push();r->count();
    }
    Splay(r,tar);
}
void Insert(int pos,int tot){
    Node *k;
    Find(pos+1,null);
    k=Root->Nxt();//在根节点的右儿子的左儿子处给插入数空出位置
    Splay(k,Root);
    for (int i=1;i<=tot;i++) scanf("%d",&a[i]);
    k=build(1,tot);//把读进来的树建成一棵Splay
    Root->ch[1]->ch[0]=k;
    k->fa=Root->ch[1];
    Splay(k,null);
}
void Delete(int pos,int tot){
    Find(pos,null);
    Find(pos+tot+1,Root);//提取区间然后删除
    Del(Root->ch[1]->ch[0]);
    Root->ch[1]->ch[0]=null;
    Root->ch[1]->count();
    Root->count();//注意及时更新
}
void MakeSame(int pos,int tot,int c){
    Find(pos,null);
    Find(pos+tot+1,Root);
    Root->ch[1]->ch[0]->Cover(c);
    Root->ch[1]->count();
    Root->count();
}
void Reverse(int pos,int tot){
    Find(pos,null);
    Find(pos+tot+1,Root);
    Root->ch[1]->ch[0]->Rever();
    Splay(Root->ch[1]->ch[0],null);
}
int GetSum(int pos,int tot){
    Find(pos,null);
    Find(pos+tot+1,Root);
    return Root->ch[1]->ch[0]->sum;
}
int main()
{
    null=new Node;*null=Node();
    head=0;tail=600000;
    for (int i=0;i<=600000;i++){
        Pool[i]=Node();q[i]=Pool+i;
    }
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    a[0]=a[n+1]=-inf;
    Root=build(0,n+1);
    for (int i=1;i<=m;i++){
        char opt[20];
        scanf("%s",opt);
        switch (opt[0]){
            case 'I':{
                int pos,tot;
                scanf("%d%d",&pos,&tot);
                Insert(pos,tot);
                break;
            }
            case 'D':{
                int pos,tot;
                scanf("%d%d",&pos,&tot);
                Delete(pos,tot);
                break;
            }
            case 'M':{
                if (opt[2]=='K'){
                    int pos,tot,c;
                    scanf("%d%d%d",&pos,&tot,&c);
                    MakeSame(pos,tot,c);
                }else printf("%d\n",Root->tMax);
                break;
            }
            case 'R':{
                int pos,tot;
                scanf("%d%d",&pos,&tot);
                Reverse(pos,tot);
                break;
            }
            case 'G':{
                int pos,tot;
                scanf("%d%d",&pos,&tot);
                printf("%d\n",GetSum(pos,tot));
                break;
            }
        }
    }
    return 0;
}

偏偏在最后出现的补充说明

码大数据结构的时候要多想一想,不同的问题有不同的适用的写法,对于维护信息的设定十分关键,有时候会大大影响程序的运行速度。

编程语言的未来走向:趋势、挑战与机遇 同时,鼓励他们接触和掌握一些专业领域的开发工具和技术框架,比如Web开发中的JavaScript、React.js,数据分析的Python(Pandas, NumPy, Matplotlib等),以及人工智能和机器学习领域的TensorFlow、PyTorch等。当前,全球范围内正积极推动编程教育的普及化,从儿童启蒙阶段到高等教育阶段,乃至终身学习的过程中,如何优化编程语言的教学方法、提高教学质量,并将其广泛应用于不同领域,是教育者与政策制定者面临的重大课题。未来,编程语言的多样化和包容性将会继续加强。 阅读详情

相关推荐

别再硬啃C代码了!用Simulink的Matlab Function模块手把手教你搭建CRC8校验模型(附完整M脚本)

本文详细介绍了如何利用Simulink的Matlab Function模块轻松实现CRC8校验模型,替代传统的C代码编写。通过可视化建模和即时验证,开发者可以高效完成算法设计,并自动生成嵌入式代码。文章包含完整的M脚本示例和工程实践技巧,特别适合嵌入式系统开发人员提升工作效率。

weixin_42520661的博客 183

[BZOJ1500]NOI2005 维修数列|splay

这题号称是noi出过最变态的数据结构题,,感觉还差不多嘛。。一开始我一直在纠结splay上的节点一点要有一个key值的啊,要是以这个数在序列中的位置作为key值的话又要插入又要删除肯定弄不了。。然后想了很久突然顿悟。。貌似我给一个初始顺序以后是不用访问key的&&找第k位的数只要写一个findkth就行了嘛。。(当时太弱) 然后我就一口气写了下来。。 对每个节点维护size,sum,maxsu

Tag_king的专栏 2015

VxWorks环境搭建与学习:vxworks6.8和workbench3.2

VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统(RTOS),是嵌入式开发环境的关键组成部分。良好的持续能力、高性能的内核以及友好的用户开发环境,在嵌入式实时操作系统领域占据一席之地。它以其良好的可靠性和卓越的实时性被广泛地应用在通信、军事、航空、航天等高精尖技术及实时性要求极高的领域中,如卫星通讯、军事演习、弹道制导、飞机导航等。

qq_41854911的博客 8469

【bzoj1500】[NOI2005]维修数列 Splay

终于打败大boss了,耗时一下午。 应该是splay维护序列题型的巅峰了吧。 这道题不能单纯的开点,因为会MLE,所以要用回收节点的过程。 说一下搞法吧: 1、插入,提取区间,递归建树 2、删除,提取区间,把删去的点用一个栈储存下来 3、修改,提取区间,打个标记 4、翻转,提取区间,打个标记 5、求和、最大连续子段和,维护一下就可以了。 WA点: 这道题不用开longlong,

Oxer的专栏 2384

kepserverEX6创建tcpserver接入自有协议(使用ucon接入)

kepserverEX6创建tcpserver接入自有协议

qq_38388813的博客 1632

用python提取PDF中各类文本内容的方法

用python提取PDF中各类文本内容的方法

安静的软件工程师 6086

bzoj1500维修数列splay

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 14759  Solved: 4832 [Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目

maxtir的博客 416

Ubuntu 20.04 系统备份和还原

最近大家Ubuntu开发环境,经常出现搭着搭着系统就挂了,于是开始琢磨了Ubuntu系统的备份和还原,以备不时之需,Linux环境搭建实在是有点太细,好多情况下,就算曾经搭建过一遍,再次搭建有些包还是忘了安装,做好备份是十分必要的。 经过了一番研究,Ubuntu备份有很多方式:根目录tar、dd、Systemback(1.0版本已经不维护了,2.0版本收费)等等,最终决定使用 —— Timesift, 因为方便一些。 文章参考:小马虎的救星——Timeshift Timeshift Timeshift,是L

Z_Paper的博客 2万+

[bzoj1500][splay]维修数列

传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=1500 sol: splay题,题解等下补 #include&lt;cstdio&gt; #include&lt;algorithm&gt; #include&lt;string&gt; #include&lt;cstring&gt; #include&lt;cstdlib&gt; ...

Gzb1128的栖息地 203

星网锐捷语音网关密码重置全攻略:两种高效恢复出厂设置方法详解

本文详细解析了星网锐捷语音网关密码重置的两种高效方法,包括通过eth1通用口和eth0管理口的操作步骤。针对不同型号设备,提供硬件连接、Web控制台登录及CRT工具使用的具体指南,帮助用户快速恢复出厂设置并重建语音环境配置。

weixin_28698059的博客 528

HyperLynx(十四)高级分析技术

如果没有查找到该模型,可使用菜单命令“Setup”→“Options”→“Directories”,打开“Set Directories”对话框,单击“Edit”按钮,在“Select Directories for IC-Model Files”对话框中将路径“…在“Assign Models”对话框中的“Port”栏找到“OUTM”端口,在其对应的“Circuit Connection”栏中选择“txout”项。将端口R75连接到“Gnd”。同样,将“EMP”连接到“V”,完成预加重设置。...

小幽余生不加糖 4948

BZOJ1500: [NOI2005]维修数列 Splay

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 12862  Solved: 4104 [Submit][Status][Discuss] 题解: Splay的巅峰之作,支持插入一堆数,删除一堆数,区间反转,区间权值覆盖,求和,求最大子序列 对于插入和删除: 因为内存只能开到500000,

Oakley 640

Google Earth Engine 实现图像随机森林分类_遥感分类全流程详解

本文将通过一段完整的GEE代码,逐步讲解如何利用Sentinel-2影像和随机森林算法,实现地表覆盖分类。代码包含等关键步骤,适合遥感入门学习!

国科大硕士在读,分享Python/GEE/Matlab/R专业代码实践,涵盖数据分析、算法开发与应用技巧等,以代码会友。 916

Splay 模板【NOI2005】 bzoj1500 维修数列

老师说写博客有助于学习和理解代码,所以从今天起,做一个写博客的人,面朝代码,春暖花开o(n_n)o。 Splay是一种可以对一个数列进行区间修改,区间反转,查询最值,查询总和等操作的数据结构(我觉得Splay的结构类似于treap,功能类似于线段树),而且能够快速实现区间的分裂与合并。 Splay与Treap的最大区别是旋转方式,Treap将树按照堆得形式维护,只需要单旋。而S

Todobe 552

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【splay】BZOJ 1500: [NOI2005]维修数列

BZOJ 3224 普通平衡树DescriptionInput输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。第2行包含N个数字,描述初始时的数列。以下M行,每行一条命令,格式参见问题描述中的表格。Output对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。Sample Input9 8 2 -6 3 5 1

puck_just_me的blog 786

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

bzoj 1500: [NOI2005]维修数列 splay

1500: [NOI2005]维修数列 Time Limit:10 SecMemory Limit:64 MBSubmit:6556Solved:1963[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。第2行包含N个数字,描述初始时的...

alex151194310的博客 170

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

[bzoj1500][NOI2005]维修数列 splay大模板

写了后就 需重写

Unlimited Code Works 298

【BZOJ1500】【NOI2005】维修数列(Splay)

【BZOJ1500】【NOI2005】维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #i...

weixin_30412167的博客 82

BZOJ 1500 [NOI2005]维修数列 Splay

Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。 第2行包含N个数字,描述初始时的数列。 以下M行,每行一条命令,格式参见问题描述中的表格。 任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。 插入的数字总数不超过4 000

I'm Growing 547

[BZOJ1500][NOI2005][Splay]维修数列

[Problem Description] [Data Structure] Splay [Analysis] Splay没话说,维护节点信息和pushdown,update与线段树有些像。 [Pay Attention] 这里有一个逗比的地方,MAX-SUM不包括空串这种情况,也就是说,就算序列里面最大的数是负数,也不能输出0,而是输出那个负数。 [Code] /**

gaotianyu1350的专栏 748

[BZOJ1500][NOI2005]维修数列 解题报告 Splay

  Portal Gun:[BZOJ1500][NOI2005]维修数列   有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了   关于这道题...该说什么好呢...网上好多人评论这道题又是难啊,又是要调很久什么的,还讲这是道平衡树的boos级别的题...看了题后,好像也没有说的这么难吧,思路比较简单,代码也不...

weixin_30794491的博客 75

【BZOJ】1500 [NOI2005]维修数列 【splay】

传送门:【BZOJ】1500 [NOI2005]维修数列

poursoul 963

[NOI2005] [BZOJ1500] 维修数列 - splay

前段日子一直在看LCT QWQ。照着板子A了魔法森林但是感觉还是不是太明白,神犇告诉我说应该先把splay学好然后码了几天找了N处错误才A了这题     splay大模板题啊。虽然程序跑得不很快,但是总算AC了qwq。 注释里面有一些提示,就是我错的地方qwq,提醒大家注意哈。     #include "algorithm" #include "iostream" #include "std

whzzt的博客 613

【BZOJ1500】[NOI2005]维修数列【Splay】

http://www.lydsy.com/JudgeOnline/problem.php?id=1500 这神题终于过了... 主要是: find()那里少写了一个pushdown()。 辣鸡回收写跪了。 /* Footprints In The Blood Soaked Snow */ #include #include using namespace s

BraketBN 490

bzoj 1500 NOI2005 维修数列 [Splay]

维修数列Time Limit: 10 Sec Memory Limit: 64 MB Submit: 11839 Solved: 3724Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。 第2行包含N个数字,描述初始时的数列。 以下M行,每行一条命令,格式参见问题描述中的表格。 任何时刻

C'est la vie. 573

[BZOJ1500][NOI2005]维修数列(splay)

题目描述传送门题解splay模板题(笑 这题是我今年1月左右看到的。记得当时只调过了样例然后交上去过了一个点就用了我一天的时间。果然我还是太傻逼。 填上了好大一个坑。 前5个都是splay的基础操作,就是第6个比较麻烦。因为要维护区间最大连续子序列和,可以维护3个值:Max子树最大连续子序列和,maxl子树自左端起最大连续子序列和,maxr子树自右端起最大连续子序列和。注意这里的Max是不允许

zyf2000 1010
上一篇: 二分图匹配——匈牙利算法の板子
下一篇: 我们都是大zz
FromATP
博客等级 码龄10年 75粉丝 163原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值