线段树(二)STEP

线段树(二)

线段树例题整理函数

Part 1:题面

传送门:https://www.luogu.com.cn/problem/P6492(靠以前传送门放错了,暴露了我在机房逛B站的事实……spa

Part 2:思路整理

问题抽象化

题目中要求咱们维护一个包含\(L、R\)序列,若是一个字序列中不包含连续的\(L\),或连续的\(R\),则称其知足要求指针

如今要求咱们的程序支持两种操做:code

一、单点修改,每次把\(L\)改成\(R\),把\(R\)改为\(L\)get

二、区间查询,查询整个序列里知足条件的最长的字串it

首先,咱们能够把问题转换为这样:给定一个\(01\)串,每次对数列中的一个数执行异或操做,维护序列中最长的知足条件的串的长度io

容易发现,本题的答案知足区间可合并性质,由一个\(0\)\(1\)组成的串依次向上统计拼接,便可获得答案class

因此咱们使用线段树能够很方便的进行区间修改和整段区间查询操做date

答案统计

如今考虑咱们须要维护什么信息以及怎么自下而上统计这些信息程序

按照本人的垃圾思路,咱们须要统计如下信息

\(一、\)最终答案:即为最长的知足条件的串

\(二、\)一个区间的最左端的字符:这决定了它可不能够与左边的区间合并

\(三、\)一个区间的最右端的字符:这决定了它可不能够与右边的区间合并

\(四、\)一个区间以最左端字符开始的最长的知足条件的串长度:这决定了它与左边的区间合并时产生的知足条件的串长度

\(五、\)一个区间以最右端字符开始的最长的知足条件的串长度:这决定了它与右边的区间合并时产生的知足条件的串长度

从下向上统计信息的时候,有如下八种状况:

这里为了简便,咱们令\(ls,rs\)分别为指向左儿子的指针和指向右儿子的指针,\(lv,rv,mv\)分别为这个区间以最左端字符开始的最长知足条件串,这个区间以最右端字符开始的最长知足条件串和这个区间内最长的知足条件串,\(l,r\)则分别表示这个区间的左端点和右端点

请注意:
为了更加清晰的理解从下向上合并的操做,咱们还须要引入一个概念——彻底串:若该区间所表明的整个串是一个知足要求的串咱们称为彻底串,一个彻底串有这些特性:
\(一、\)\(lc\neq rc\)
\(二、\)\(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);
}

\(一、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\)

\(二、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\)

\(三、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\)

\(四、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\)

\(五、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\)

\(六、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\)

\(七、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\)

\(八、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;
}
相关文章
相关标签/搜索