线段树(二)STEP
线段树(二)
线段树例题整理
Part 1:题面
传送门:https://www.luogu.com.cn/problem/P6492(靠之前传送门放错了,暴露了我在机房逛B站的事实……
Part 2:思路整理
问题抽象化
题目中要求我们维护一个包含\(L、R\)序列,如果一个字序列中不包含连续的\(L\),或连续的\(R\),则称其满足要求
现在要求我们的程序支持两种操作:
1、单点修改,每次把\(L\)改为\(R\),把\(R\)改成\(L\)
2、区间查询,查询整个序列里满足条件的最长的字串
首先,我们可以把问题转换为这样:给定一个\(01\)串,每次对数列中的一个数执行异或操作,维护序列中最长的满足条件的串的长度
容易发现,本题的答案满足区间可合并性质,由一个\(0\)或\(1\)组成的串依次向上统计拼接,即可得到答案
所以我们使用线段树可以很方便的进行区间修改和整段区间查询操作
答案统计
现在考虑我们需要维护什么信息以及怎么自下而上统计这些信息
按照本人的垃圾思路,我们需要统计以下信息
\(1、\)最终答案:即为最长的满足条件的串
\(2、\)一个区间的最左端的字符:这决定了它可不可以与左边的区间合并
\(3、\)一个区间的最右端的字符:这决定了它可不可以与右边的区间合并
\(4、\)一个区间以最左端字符开始的最长的满足条件的串长度:这决定了它与左边的区间合并时产生的满足条件的串长度
\(5、\)一个区间以最右端字符开始的最长的满足条件的串长度:这决定了它与右边的区间合并时产生的满足条件的串长度
从下向上统计信息的时候,有以下八种情况:
这里为了简便,我们令\(ls,rs\)分别为指向左儿子的指针和指向右儿子的指针,\(lv,rv,mv\)分别为这个区间以最左端字符开始的最长满足条件串,这个区间以最右端字符开始的最长满足条件串和这个区间内最长的满足条件串,\(l,r\)则分别表示这个区间的左端点和右端点
请注意:
为了更加清晰的理解从下向上合并的操作,我们还需要引入一个概念——完全串:若该区间所代表的整个串是一个满足要求的串我们称为完全串,一个完全串有这些特性:
\(1、\)\(lc\neq rc\)
\(2、\)\(lv=rv=mv=(r-l+1)\)
显然完全串的统计方式和普通串的统计方式应该不同
我们用这样一个函数来判断这个区间是不是完全串:
inline bool copst(const int L,const int R,const int Len) { return (Len==R-L+1); }//是否为完全串
//下面我们用copst(ls||rs)==true||false代表左右儿子是否是完全串
我们用这个函数返回三个参数的最大值
inline int smax(const int a,const int b,const int c){
const int d=max(a,b);
return max(c,d);
}
\(1、copst(ls)=true,copst(rs)=true,ls\rightarrow rc\neq rs\rightarrow lc\)(可以合并)
\(lv=r-l+1,rv=r-l+1,mv=r-l+1\)
\(lc=ls\rightarrow lc,rc=rs\rightarrow rc\)
\(2、copst(ls)=true,copst(rs)=true,ls\rightarrow rc=rs\rightarrow lc\)(不能合并)
\(lv=ls\rightarrow lv,rv=rs\rightarrow rv,mv=max(ls\rightarrow mv,rs\rightarrow mv)\)
\(lc=ls\rightarrow lc,rc=rs\rightarrow rc\)
\(3、copst(ls)=false,copst(rs)=true,ls\rightarrow rc\neq rs\rightarrow lc\)(可以合并)
\(lv=ls\rightarrow lv,mv=smax(ls\rightarrow mv,ls\rightarrow rv+rs\rightarrow lv,rs\rightarrow mv),rv=ls\rightarrow rv+rs\rightarrow rv\)
\(lc=ls\rightarrow lc,rc=rs\rightarrow rc\)
\(4、copst(ls)=false,copst(rs)=true,ls\rightarrow rc=rs\rightarrow lc\)(不能合并)
\(lv=ls\rightarrow lv,mv=max(ls\rightarrow mv,rs\rightarrow mv),rv=rs\rightarrow rv\)
\(lc=ls\rightarrow lc,rc=rs\rightarrow rc\)
\(5、copst(ls)=true,copst(rs)=false,ls\rightarrow rc\neq rs\rightarrow lc\)(可以合并)
\(lv=ls\rightarrow mv+rs\rightarrow lv,mv=smax(ls\rightarrow mv,ls\rightarrow rv+rs\rightarrow lv,rs\rightarrow mv),rv=rs\rightarrow rv\)
\(lc=ls\rightarrow lc,rc=rs\rightarrow rc\)
\(6、copst(ls)=true,copst(rs)=false,ls\rightarrow rc=rs\rightarrow lc\)(不能合并)
\(lv=ls\rightarrow lv,mv=max(ls\rightarrow mv,rs\rightarrow mv),rv=rs\rightarrow rv\)
\(lc=ls\rightarrow lc,rc=rs\rightarrow rc\)
\(7、copst(ls)=false,copst(rs)=false,ls\rightarrow rc\neq rs\rightarrow lc\)(可以合并)
\(lv=ls\rightarrow mv+rs\rightarrow mv,mv=ls\rightarrow mv+rs\rightarrow mv,rv=ls\rightarrow mv+rs\rightarrow mv\)
\(lc=ls\rightarrow lc,rc=rs\rightarrow rc\)
\(8、copst(ls)=false,copst(rs)=false,ls\rightarrow rc=rs\rightarrow lc\)(可以合并)
\(lv=ls\rightarrow lv,mv=max(ls\rightarrow mv,rs\rightarrow mv),rv=rs\rightarrow rv\)
\(lc=ls\rightarrow lc,rc=rs\rightarrow rc\)
Part 3:\(Code\)
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn=200005;
int n,q;
inline int smax(const int a,const int b,const int c){
const int d=max(a,b);
return max(d,c);
}
struct sag{//这里作者又拼错了qwq,凑合看叭
int lc,rc,lv,rv,mv;
int l,r;
sag *ls,*rs;
inline void push_up(){
bool liscop=copst(ls->l,ls->r,ls->mv);
bool riscop=copst(rs->l,rs->r,rs->mv);
if(liscop==1&&riscop==0&&ls->rc!=rs->lc){
lv=ls->mv+rs->lv;
mv=smax(ls->mv,ls->rv+rs->lv,rs->mv);
rv=rs->rv;
lc=ls->lc;
rc=rs->rc;
}
if(liscop==1&&riscop==0&&ls->rc==rs->lc){
lv=ls->lv;
mv=max(ls->mv,rs->mv);
rv=rs->rv;
lc=ls->lc;
rc=rs->rc;
}
if(liscop==0&&riscop==1&&ls->rc!=rs->lc){
lv=ls->lv;
mv=smax(ls->mv,ls->rv+rs->lv,rs->mv);
rv=ls->rv+rs->rv;
lc=ls->lc;
rc=rs->rc;
}
if(liscop==0&&riscop==1&&ls->rc==rs->lc){
lv=ls->lv;
mv=max(ls->mv,rs->mv);
rv=rs->rv;
lc=ls->lc;
rc=rs->rc;
}
if(liscop==0&&riscop==0&&ls->rc!=rs->lc){
lv=ls->lv;
mv=smax(ls->mv,ls->rv+rs->lv,rs->mv);
rv=rs->rv;
lc=ls->lc;
rc=rs->rc;
}
if(liscop==0&&riscop==0&&ls->rc==rs->lc){
lv=ls->lv;
mv=max(ls->mv,rs->mv);
rv=rs->rv;
lc=ls->lc;
rc=rs->rc;
}
if(liscop==1&&riscop==1&&ls->rc!=rs->lc){
lv=ls->mv+rs->mv;
mv=ls->mv+rs->mv;
rv=ls->mv+rs->mv;
lc=ls->lc;
rc=rs->rc;
}
if(liscop==1&&riscop==1&&ls->rc==rs->lc){
lv=ls->lv;
mv=max(ls->mv,rs->mv);
rv=rs->rv;
lc=ls->lc;
rc=rs->rc;
}
}
inline bool copst(const int L,const int R,const int Len) { return (Len==R-L+1); }//是否为完全串
inline bool in_range(const int L,const int R) { return (L<=l)&&(r<=R); }
inline bool outof_range(const int L,const int R) { return (r<L)||(R<l); }
void update(const int L,const int R){
if(in_range(L,R)){
lc=(lc==1)?0:1;
rc=lc;
lv=rv=mv=1;
}else if(!outof_range(L,R)){
ls->update(L,R);
rs->update(L,R);
push_up();//由孩子向父亲统计信息
}
}
}*rot;
sag byte[maxn<<1],*pool=byte;
sag* New(const int L,const int R){
sag *u=pool++;
u->l=L,u->r=R;
if(L==R){
u->ls=u->rs=NULL;
u->lc=u->rc=0;
u->mv=u->lv=u->rv=1;
}else{
int Mid=(L+R)>>1;
u->ls=New(L,Mid);
u->rs=New(Mid+1,R);
u->push_up();
}
return u;
}
int main(){
scanf("%d%d",&n,&q);
rot=New(1,n);
for(int x,i=0;i<q;i++){
scanf("%d",&x);
rot->update(x,x);
printf("%d\n",smax(rot->lv,rot->rv,rot->mv));
}
return 0;
}
线段树(二)STEP的更多相关文章
- UVA 11297 线段树套线段树(二维线段树)
题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要 不同的处理方式,非叶子形成的 ...
- BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j) if(a[ ...
- 洛谷 P4088 [USACO18FEB] Slingshot P(线段树+二维数点)
题目链接 题意:有一个数轴,上面有 \(n\) 个传送门,使用第 \(i\) 个传送门,你可以从 \(x_i\) 走到 \(y_i\),花费的时间为 \(t_i\) 秒.你的速度为 \(1\) 格/秒 ...
- CodeForces 242E - XOR on Segment 二维线段树?
今天练习赛的题....又是线段树的变换..拿到题我就敲了个点更新区间查询的..果断超时...然后想到了可以将每个数与合表示成不进位的二进制数..这样就可以区间进行更新了..比赛的时候写搓了..刚重写了 ...
- Luck and Love(二维线段树)
Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- POJ2155 Matrix 二维线段树
关键词:线段树 二维线段树维护一个 维护一个X线段的线段树,每个X节点维护一个 维护一个Y线段的线段树. 注意,以下代码没有PushDownX.因为如果要这么做,PushDownX时,由于当前X节点的 ...
- Wannafly Winter Camp 2020 Day 5I Practice for KD Tree - 二维线段树
给定一个 \(n \times n\) 矩阵,先进行 \(m_1 \leq 5e4\) 次区间加,再进行 \(m_2 \leq 5e5\) 次询问,每次询问要求输出矩形区间内的最大数.\(n \leq ...
- HDU 3642 Get The Treasury 线段树+分层扫描线
http://www.acmerblog.com/hdu-3642-get-the-treasury-6603.html 学习:三维就是把竖坐标离散化分层,每一层进行线段树二维面积并就好了
- [IOI2018]狼人——kruskal重构树+可持久化线段树
题目链接: IOI2018werewolf 题目大意:给出一张$n$个点$m$条边的无向图,点和边可重复经过,一个狼人初始为人形,有$q$次询问,每次询问要求人形态只能处于编号不小于$L$的点,狼形态 ...
- HDU1823-Luck and Love-二维线段树(模板)
题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=1823 好吧,给这题跪了. ..orz.... 一道非常基础的二维线段树的模板题: 可是细节非常多:尤 ...
随机推荐
- 题解 洛谷 P3734 【[HAOI2017]方案数】
可以先考虑没有障碍物的情况,设计状态\(f_{i,j,k}\),表示到达坐标 \((x,y,z)\)二进制下,\(x\)有\(i\)位,\(y\)有\(j\)位,\(z\)有\(k\)位的方案数. 得 ...
- django-rest-framework-源码解析001-整体框架
简介 Django Rest Framework是一个强大且灵活的工具包,主要用以构建RESTful风格的Web API. Django REST Framework(简称DRF)可以在Django的 ...
- Spring事务处理时自我调用
1.预备知识 aop概念请参考[http://www.iteye.com/topic/1122401]和[http://jinnianshilongnian.iteye.com/blog/141859 ...
- Mybatis(三)动态sql语句
动态sql语句操作 1.MyBatis中#{ }和${ }的区别 在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析.mybatis 为我们提供了两种支 ...
- JavaScript高级程序设计(第三版) 5/25
第三章 基本概念 1.任何语言的核心都必然会描述这门语言最基本的工作原理.而描述的内容通常都要涉及这门语言的语法.操作符.数据类型.内置功能等用于构建复杂解决方案的基本概念. 2.浮点数值,该数值中必 ...
- java实现经典坦克大战及源代码下载
坦克大战源码 (点击即可下载) 链接:https://pan.baidu.com/s/1m9aVheaquwxGKjYQrb72AA 提取码:j8dr see you ! 觉得有用的话点个赞再走
- PHP xml_error_string() 函数
定义和用法 xml_error_string() 函数获取 XML 解析器的错误描述.高佣联盟 www.cgewang.com 如果成功,该函数则返回错误描述.如果失败,则返回 FALSE. 语法 x ...
- Skill 脚本演示 ycCommonCenterMos.skl
https://www.cnblogs.com/yeungchie/ ycCommonCenterMos.skl 自动生成一个共质心差分对 Mos ,可以自定布局类型. 回到目录
- 解决痛苦的方法/cy
这篇文章 源于我所有痛苦的回忆. 由于痛苦太多了 体会完了 所以 觉得这些都不算是什么大问题了 所以 这里 是解决痛苦的方法. 真的很痛苦的话 可以这样 对着全班人喊你们 都没我强 因为 你们都没有我 ...
- ElasticSearch 基本概念 and 索引操作 and 文档操作 and 批量操作 and 结构化查询 and 过滤查询
基本概念 索引: 类似于MySQL的表.索引的结构为全文搜索作准备,不存储原始的数据. 索引可以做分布式.每一个索引有一个或者多个分片 shard.每一个分片可以有多个副本 replica. 文档: ...