線段樹(二)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;
}
相關文章
相關標籤/搜索