[BZOJ1500][NOI2005]维修数列---解题报告
Portal Gun:[BZOJ1500][NOI2005]维修数列
有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了
关于这道题...该说什么好呢...网上好多人评论这道题又是难啊,又是要调很久什么的,还讲这是道平衡树的boos级别的题...看了题后,好像也没有说的这么难吧,思路比较简单,代码也不是特别长,splay也还算好码,虽然我这边现学 splay 现做确实花了不少时间,但总体来说这道题还是比较简单的.
题目中的很多操作( INSERT,DELETE,MAKE-SAME,REVERSE )都有一个共性,是要操作从 pos 开始,往后一段长度的区间,这儿就有这样一个小套路:
1.对于 INSERT ,我们把 pos 旋转到根, pos+1 旋转到根的右儿子,显然这时 pos+1 的左儿子为空,那么我们要插入就好办了,将要插入的序列建成一颗小树,直接将小树的根插入到 pos 的左儿子就完成了整个操作.
2. 同样,对于其他几个操作,我们需要调整的是 pos 到 pos+tot 这一段,像 INSERT 那样,将 pos 旋转到根, pos+tot 旋转到根的右儿子,这时要操作的就是 pos+tot 的左儿子,这应该很好理解吧.以上是这些操作的共性.
详细的,对于 DELETE ,我们从 pos+tot 的左儿子开始,向下递归删除,为了防止空间的浪费,可以开个栈来存放被删除节点以备后面的 INSERT 使用. MAKE-SMAE 和 REVERSE 也都是递归处理,给每个节点分别记 tag 和 rev ,tag 表示是否进行 MAKE-SAME 操作, rev 表示是否 REVERSE ,就像线段树里的 lazy ,如果你想问 REVERSE 怎么完成, swap 不就得了...
至于 GET-SUM 和 MAX-SUM ,线段树你会吧......子节点递归更新父亲就好了......
以下是代码( 建议从 main() 开始阅读 ):
先容我吐槽几句:这个 gi() 好丑......本来我的 gi() 只有两行的,但两行的 gi() 放上来会超边框非常不爽,只好扩成现在这个......对于这个 gi() ,想吐槽的发到评论全就好了......
#include<iostream> #include<cstdio> #include<cstdlib> #define inf (1<<30) #define maxn (510010) #define ll long long #define il inline #define RG register using namespace std; il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar(); if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; } struct node{ bool rev,tag; int fa,son[2],w,size,sum,lmax,rmax,ans; }t[maxn];//lmax表示左端点在内的最大区间和,rmax相反,ans为整个区间的最大区间和 int n,Q,cnt,root,sta[maxn],top,a[maxn]; il int newnode(){ int num; if(top) num=sta[top--]; else num=++cnt; t[num].son[0]=t[num].son[1]=t[num].fa=0; t[num].tag=t[num].rev=0; t[num].size=1; t[num].sum=t[num].w=t[num].lmax=t[num].rmax=-inf; return num; } il void up(int x){ if(!x) return ; int ls=t[x].son[0],rs=t[x].son[1]; t[x].size=t[ls].size+t[rs].size+1; t[x].sum=t[ls].sum+t[rs].sum+t[x].w; t[x].lmax=max(t[ls].lmax,t[ls].sum+t[x].w+max(0,t[rs].lmax) ); t[x].rmax=max(t[rs].rmax,t[rs].sum+t[x].w+max(0,t[ls].rmax) ); t[x].ans=max( max(t[ls].ans,t[rs].ans),max(0,t[ls].rmax)+t[x].w+max(0,t[rs].lmax) ); } il void build_tree(RG int x,RG int l,RG int r){ RG int mid=(l+r)>>1; t[x].w=a[mid]; if(l==r){ t[x].sum=t[x].lmax=t[x].rmax=t[x].ans=t[x].w; t[x].size=1; return ; } if(l<mid){ t[x].son[0]=newnode(),t[ t[x].son[0] ].fa=x; build_tree(t[x].son[0],l,mid-1); } if(r>mid){ t[x].son[1]=newnode(),t[ t[x].son[1] ].fa=x; build_tree(t[x].son[1],mid+1,r); } up(x); } il void reverse(int x){ //翻转的副操作 if(!x) return ; swap(t[x].lmax,t[x].rmax); //!!别落下了!! swap(t[x].son[0],t[x].son[1]); t[x].rev^=1; } il void replace(int x,int v){ //修改的副操作 if(!x) return ; t[x].w=v,t[x].sum=v*t[x].size; t[x].lmax=t[x].rmax=t[x].ans=max(v,v*t[x].size); t[x].tag=1,t[x].rev=0; } il void push_down(int x){ //标记下放 if(t[x].rev){ if( t[x].son[0] ) reverse(t[x].son[0]); if( t[x].son[1] ) reverse(t[x].son[1]); t[x].rev=0; } if(t[x].tag){ if( t[x].son[0] ) replace(t[x].son[0],t[x].w); if( t[x].son[1] ) replace(t[x].son[1],t[x].w); t[x].tag=0; } } il void down(int x){ if(t[x].fa) down(t[x].fa); push_down(x); } il int get_kth(int x,int k){ //查第 k 个节点编号 push_down(x); if(t[ t[x].son[0] ].size==k-1) return x; if(t[ t[x].son[0] ].size>k-1) return get_kth(t[x].son[0],k); else return get_kth(t[x].son[1],k-t[ t[x].son[0] ].size-1); } il int dir(int x){ return x==t[ t[x].fa ].son[1]; } il void rotate(int x){ int y,z,a,b,c; y=t[x].fa,z=t[y].fa; b=dir(x),a=t[x].son[!b]; if(z==0) root=x; else{ c=dir(y),t[z].son[c]=x; } t[x].fa=z,t[y].fa=x,t[x].son[!b]=y,t[y].son[b]=a; if(a) t[a].fa=y; up(y),up(x); } il void splay(int x,int goal){ down(x); int y,z,b,c; while(t[x].fa!=goal){ y=t[x].fa,z=t[y].fa; if(z==goal) rotate(x); else{ b=dir(x),c=dir(y); if(b^c){ rotate(x),rotate(x); } else{ rotate(y),rotate(x); } } } } il void INSERT(int pos,int tot){ //插入 for(RG int i=1;i<=tot;i++) a[i]=gi(); int x=get_kth(root,pos+1); splay(x,0); int y=get_kth(t[x].son[1],1); splay(y,x); t[y].son[0]=newnode(); t[ t[y].son[0] ].fa=y; build_tree(t[y].son[0],1,tot); up(y),up(x); } il void erase(int x){ //删除的副操作 if(!x) return ; sta[++top]=x;//回收节点 if(t[x].son[0]) erase(t[x].son[0]); if(t[x].son[1]) erase(t[x].son[1]); } il void DELETE(int pos,int tot){ //删除 int x=get_kth(root,pos); splay(x,0); int y=get_kth(t[x].son[1],tot+1); splay(y,x); erase( t[y].son[0] ); t[ t[y].son[0] ].fa=0,t[y].son[0]=0; up(y),up(x); } il void MAKE_SAME(int pos,int tot,int v){ //修改 int x=get_kth(root,pos); splay(x,0); int y=get_kth(t[x].son[1],tot+1); splay(y,x); replace(t[y].son[0],v); up(y),up(x); } il void REVERSE(int pos,int tot){ //翻转 int x=get_kth(root,pos); splay(x,0); int y=get_kth(t[x].son[1],tot+1); splay(y,x); reverse(t[y].son[0]); up(y),up(x); } il int QUERY(int pos,int tot){ //查询 int x=get_kth(root,pos); splay(x,0); int y=get_kth(t[x].son[1],tot+1); splay(y,x); return t[t[y].son[0]].sum; } il void init(){ t[0].lmax=t[0].rmax=t[0].ans=-inf; cnt=2,root=1; t[1].fa=0,t[1].size=2,t[1].son[1]=2,t[1].w=t[1].sum=t[1].lmax=t[1].rmax=-inf; t[2].fa=1,t[2].size=1,t[2].w=t[2].sum=t[2].lmax=t[2].rmax=-inf; n=gi(),Q=gi(); for(RG int i=1;i<=n;i++) a[i]=gi(); t[2].son[0]=newnode(),t[t[2].son[0]].fa=2; build_tree(t[2].son[0],1,n); up(2),up(1); } il void work(){ int x,y,z; char s[15]; while(Q--){ scanf("%s",s); if(s[0]=='I'){ x=gi(),y=gi(); INSERT(x,y); } if(s[0]=='D'){ x=gi(),y=gi(); DELETE(x,y); } if(s[4]=='-'){ x=gi(),y=gi(),z=gi(); MAKE_SAME(x,y,z); } if(s[0]=='R'){ x=gi(),y=gi(); REVERSE(x,y); } if(s[0]=='G'){ x=gi(),y=gi(); printf("%d\n",QUERY(x,y)); } if(s[2]=='X') printf("%d\n",t[root].ans); } } int main(){ init(); work(); return 0; }
[BZOJ1500][NOI2005]维修数列---解题报告的更多相关文章
- [BZOJ1500][NOI2005]维修数列 解题报告 Splay
Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...
- bzoj千题计划221:bzoj1500: [NOI2005]维修数列(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=1500 1.覆盖标记用INF表示无覆盖标记,要求可能用0覆盖 2.代表空节点的0号节点和首尾的两个虚拟 ...
- [bzoj1500][NOI2005]维修数列_非旋转Treap
维修数列 bzoj-1500 NOI-2005 题目大意:给定n个数,m个操作,支持:在指定位置插入一段数:删除一个数:区间修改:区间翻转.查询:区间和:全局最大子序列. 注释:$1\le n_{ma ...
- splay模板三合一 luogu2042 [NOI2005]维护数列/bzoj1500 [NOI2005]维修数列 | poj3580 SuperMemo | luogu3391 【模板】文艺平衡树(Splay)
先是维修数列 题解看这里,但是我写的跑得很慢 #include <iostream> #include <cstdio> using namespace std; int n, ...
- BZOJ1500[NOI2005]维修数列
Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一 ...
- BZOJ1500: [NOI2005]维修数列[splay ***]
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 12278 Solved: 3880[Submit][Statu ...
- [bzoj1500][NOI2005]维修数列——splay
题目 题解 这道题可以说是数列问题的大BOSS,也算是这一周来学习splay等数据结构的一个总结. 我们一个一个地看这些操作. 对于操作1,我们首先建一棵子树,直接接上原树即可. 对于操作2,我们找到 ...
- BZOJ1500 [NOI2005]维修数列-fhq_Treap
题面见这里 反正是道平衡树,就拿 fhq_Treap 写了写... 这道题思路基本是围绕“用 Treap 维护中序遍历” 和 中序遍历的性质 来进行的操作 所以就可以类比线段树进行一些操作 1. 建树 ...
- BZOJ1500: [NOI2005]维修数列 [splay序列操作]【学习笔记】
以前写过这道题了,但我把以前的内容删掉了,因为现在感觉没法看 重写! 题意: 维护一个数列,支持插入一段数,删除一段数,修改一段数,翻转一段数,查询区间和,区间最大子序列 splay序列操作裸题 需要 ...
随机推荐
- Java中SimpleDateFormat用法详解
所有已实现的接口: Serializable, Cloneable SimpleDateFormat 是一个以与语言环境有关的方式来格式化和解析日期的具体类.它允许进行格式化(日期 -> 文本) ...
- JAVA下JSON的类型输出及使用
JSON类型的输出: import java.util.ArrayList; import java.util.HashMap; import net.sf.json.JSONArray; impor ...
- [转] DDD领域驱动设计(三) 之 理论知识收集汇总
最近一直在学习领域驱动设计(DDD)的理论知识,从网上搜集了一些个人认为比较有价值的东西,贴出来和大家分享一下: 我一直觉得不要盲目相信权威,比如不能一谈起领域驱动设计,就一定认为国外的那个Eric ...
- Python数据类型及其方法详解
Python数据类型及其方法详解 我们在学习编程语言的时候,都会遇到数据类型,这种看着很基础也不显眼的东西,却是很重要,本文介绍了python的数据类型,并就每种数据类型的方法作出了详细的描述,可供知 ...
- Tomcat、JBOSS、WebSphere、WebLogic、Apache等技术概述
Tomcat:应用也算非常广泛的web服务器,支持部分j2ee,免费,出自apache基金组织 JBoss:开源的应用服务器,比较受人喜爱,免费(文档要收费) Weblogic:应该说算是业界 ...
- Javaee需不需要培训?培训完可以顺利找到工作吗?
Javaee需不需要培训?培训完可以顺利找到工作吗? 在IT行业中Java以它通用性.高效性.平台移植性和安全性遍布各个领域,它的火热也给IT市场发展带来一定影响,随着Java技术的广泛运营,企业对J ...
- 【面经】腾讯和YY实习生面试总结
[前言] 之前的四月份和五月份各面试了腾讯和YY的暑假实习,腾讯的失败了,YY的成功了.面试中我总会遇到自己不懂的,所幸的是不懂的越来越少,自己也一步一脚印得攻克自己不懂的.此时六月份的我再回顾起来, ...
- 遇到attemp to invoke virtual method
这个很大原因是没有预先初始化sdk,检查application的配置是否配置了application:name
- 解决ubuntu不能安装g++的问题
下面提供一种解决方法,解决方法不唯一 首先贴出错误原因: 上文是g++-4.8不能下载,所以退而求其次,指定版本4.7,不下载最新的 解决方法如下: 安装成功后而已查看版本信息确认 使用g++-4.7 ...
- 关于Android log拿不到的情况
遇到很多开发者说crash了,log没有看到..出现类似情况的基本原因是因为现在的国产厂商如crash了会直接将进程杀掉,于是你的studio就看不到了,可以往下面几个方向去想办法找到crash的lo ...