线段树(二)

线段树例题整理

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. k_means算法+python实现

    文章目录 一.原理 二.算法步骤 三.实例如下: 四.python代码实现: 一.原理 K均值算法使用的聚类准则函数是误差平方和准则,通过反复迭代优化聚类结果,使所有样本到各自所属类别的中心的距离平方 ...

  2. R星游戏如何绑定二次验证码_虚拟MFA_两步验证_谷歌身份验证器?

    一般点账户名——设置——安全设置中开通虚拟MFA两步验证 具体步骤见链接 R星游戏如何绑定二次验证码_虚拟MFA_两步验证_谷歌身份验证器? 二次验证码小程序于谷歌身份验证器APP的优势 1.无需下载 ...

  3. Android 文件存储浅析

    最近做的一个需求和文件存储有关系.由于之前没有系统梳理过,对文件存储方面的知识一直很懵懂.趁着周末有时间,赶紧梳理一波. 这首从网上找到的一张图,很好的概括了外部存储和内部存储. 下面我们再来具体介绍 ...

  4. 443端口被占用无法启动解决办法(如何查找进程ID)

    摘自CSDN博客,原文地址:http://blog.csdn.net/pet8766/article/details/8186955 netstat -ano|findstr "443&qu ...

  5. circle踢人(约瑟夫环) c++

    这里更新指针法,真的每句都是坑 (寥寥数十句,句句都是坑) // // Created by snnnow on 2020/4/12. //question:转圈,一共N个人,数到M的出列,求最后一个 ...

  6. 2020HDU多校第三场 1005 Little W and Contest

    Little W and Contest Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/O ...

  7. 06_Python基础课程

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"软件测试"获取视频和教程资料! b站在线视频 Pyth ...

  8. PHP 是什么?简介下

    PHP 是服务器端脚本语言. 您应当具备的基础知识 在继续学习之前,您需要对以下知识有基本的了解: HTML CSS PHP 是什么? PHP(全称:PHP:Hypertext Preprocesso ...

  9. PHP isset() 函数

    isset() 函数用于检测变量是否已设置并且非 NULL.高佣联盟 www.cgewang.com 如果已经使用 unset() 释放了一个变量之后,再通过 isset() 判断将返回 FALSE. ...

  10. [草稿]Skill 中的map

    https://www.cnblogs.com/yeungchie/ Skill 中的map map mapc mapcan mapcar mapcon mapinto maplist