线段树例题整理
线段树
线段树例题整理
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;
}