线段树(二)

线段树例题整理

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的更多相关文章

  1. UVA 11297 线段树套线段树(二维线段树)

    题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要  不同的处理方式,非叶子形成的 ...

  2. 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[ ...

  3. 洛谷 P4088 [USACO18FEB] Slingshot P(线段树+二维数点)

    题目链接 题意:有一个数轴,上面有 \(n\) 个传送门,使用第 \(i\) 个传送门,你可以从 \(x_i\) 走到 \(y_i\),花费的时间为 \(t_i\) 秒.你的速度为 \(1\) 格/秒 ...

  4. CodeForces 242E - XOR on Segment 二维线段树?

    今天练习赛的题....又是线段树的变换..拿到题我就敲了个点更新区间查询的..果断超时...然后想到了可以将每个数与合表示成不进位的二进制数..这样就可以区间进行更新了..比赛的时候写搓了..刚重写了 ...

  5. Luck and Love(二维线段树)

    Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...

  6. POJ2155 Matrix 二维线段树

    关键词:线段树 二维线段树维护一个 维护一个X线段的线段树,每个X节点维护一个 维护一个Y线段的线段树. 注意,以下代码没有PushDownX.因为如果要这么做,PushDownX时,由于当前X节点的 ...

  7. Wannafly Winter Camp 2020 Day 5I Practice for KD Tree - 二维线段树

    给定一个 \(n \times n\) 矩阵,先进行 \(m_1 \leq 5e4\) 次区间加,再进行 \(m_2 \leq 5e5\) 次询问,每次询问要求输出矩形区间内的最大数.\(n \leq ...

  8. HDU 3642 Get The Treasury 线段树+分层扫描线

    http://www.acmerblog.com/hdu-3642-get-the-treasury-6603.html 学习:三维就是把竖坐标离散化分层,每一层进行线段树二维面积并就好了

  9. [IOI2018]狼人——kruskal重构树+可持久化线段树

    题目链接: IOI2018werewolf 题目大意:给出一张$n$个点$m$条边的无向图,点和边可重复经过,一个狼人初始为人形,有$q$次询问,每次询问要求人形态只能处于编号不小于$L$的点,狼形态 ...

  10. HDU1823-Luck and Love-二维线段树(模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=1823 好吧,给这题跪了. ..orz.... 一道非常基础的二维线段树的模板题: 可是细节非常多:尤 ...

随机推荐

  1. 04 . Filebeat简介原理及配置文件和一些案例

    简介 Beats轻量型数据采集器 Beats 平台集合了多种单一用途数据采集器.它们从成百上千或成千上万台机器和系统向 Logstash 或 Elasticsearch 发送数据. Beats系列 全 ...

  2. 题解 洛谷 P3710 【方方方的数据结构】

    因为有撤销操作,所以修改操作可能会只会存在一段时间,因此把时间看作一维,被修改的序列看作一维. 可以把操作都离线下来,对于每个修改操作,就是在二维平面上对一个矩形进行修改,询问操作,就是查询单点权值. ...

  3. 遍历map的6种方式

    1,平时开发中对map的使用很多,然后发现了很多map可能存在的各种问题:如HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容量 7 次被迫扩大,resize ...

  4. maven项目原型(idea)

    1: internal -> appfuse-basic-jsf (创建一个基于Hibernate,Spring和JSF的Web应用程序的原型) 2: internal -> appfus ...

  5. Horse Pro(带负坐标的bfs搜索)

    Horse Pro bfs搜索,但图中存在负值坐标,两种方法解决. 用数组标记,将原点设为300,300 用map标记 http://oj.jxust.edu.cn/contest/Problem?i ...

  6. vue-resource(搬运)

    一.vue-resource特点vue-resource插件具有以下特点: 1. 体积小vue-resource非常小巧,在压缩以后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比 ...

  7. ELK5.6.4+Redis+Filebeat+Nginx(CentOS7.4)

    下载地址: Elasticsearhc: https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.4.tar.gz ...

  8. PHP设计模式之----简单工厂模式

    定义个抽象的类(或接口),让子类去继承(实现)它 abstract class Operation { abstract public function getValue($num1, $num2); ...

  9. 数据库层级关系转换为树结构的json

    原文链接:https://blog.csdn.net/Tonysdyp/article/details/80987959 首先是数据库设计: 通过查询数据库,将全局数据作为一个ArrayList< ...

  10. 读/写docx文件

    安装 pip install python-docx 1.建立新Word文档 建立新文档需要调用Document对象的save方法,一个Document对象代表一个Word文档,该方法的参数是保存的文 ...