Luogu P2572 序列操作


(是道線段樹好題√)

題目鏈接

題外話:這道題我也不知道卡了自己多少天,從初賽之前就開始做,一直到現在才a掉(時間跨度得有將近十天了吧?)

線段樹,嗯,好像很簡單的樣子。

但事實上因為自己太菜了,卡了好久;

第一遍的思路簡單的很,因為完全沒有考慮標記下傳的順序問題,qf(取反)標記和chg(修改)標記各自下傳各自的,於是乎就一直10分10分(沒有好好寫線段樹Ⅱ的鍋),咋改都不對,也沒看出自己錯在哪了;

然后被建議重構代碼,於是嘗試暴力出奇跡,\(O(nm)的暴力+O_2\)結果拿到了90pts??(jyy問號),特別迷惑;

Solution:

共有5個操作:(分別為

0 a b 把[a, b]區間內的所有數全變成0

1 a b 把[a, b]區間內的所有數全變成1

2 a b 把[a,b]區間內的所有數全部取反,也就是說把所有的0變成1,把所有的1變成0

3 a b 詢問[a, b]區間內總共有多少個1

4 a b 詢問[a, b]區間內最多有多少個連續的1

要想完成這以上五個操作,在線段樹上需要維護以下信息:

\(t[k].sum\) 記錄k節點對應區間共有多少個1

\(t[k].L[0/1]\)分別記錄k節點對應區間的左邊有幾個連續的0/1

\(t[k].R[0/1]\)分別記錄k節點對應區間的右邊有幾個連續的0/1

↑維護左右連續0/1的個數,是因為在合並兩個區間時,最長的連續的個數有可能來自左區間右側和右區間左側的合並

\(t[k].mx[0/1]\)記錄k節點對應區間最長連續0/1的個數

兩個標記:

\(t[k].qf\) 取反標記 0>不取反 1>取反

$t[k].chg $ 修改標記 -1>不修改 0> 修改為0 1==>修改為1

對於\(t[k].L[0/1],t[k].R[0/1],t[k].mx[0/1]\)的維護需要注意區間合並時可能會產生更長的連續段,要考慮並且維護,建樹、修改、查詢以及對應的重新維護區間的update此處省略…字,下面重點講pushdown:

因為有兩個不同的標記,在下傳標記時要考慮先下傳哪一個:

首先要明確是區間對於這棵線段樹來說,取反標記和修改標記是無法通過modify函數的修改同時存在的(都pushdown掉了所以不會同時存在w)

啊,是凌亂的lz,我該怎么講明白這個標記下傳的問題

先講下傳規則再來感性李姐叭:

1.對於一個既有修改標記又有取反標記的節點,我們忽略取反標記,只下傳修改標記

2.如果只有取反標記,又要分為兩種情況:

  1. 要下傳的子節點有修改標記,那么直接將修改標記取反,不下傳取反標記;
  2. 要下傳的子節點沒有修改標記,將子節點的取反標記取反;

然后交換0/1的信息(swap大法好√)

最后不要忘記將當前節點的標記清空。

所以如果既有修改標記又有取反標記,那么取反標記一定是通過它的祖先節點下傳的,而在下傳時,修改標記的值就已經相應的被取反了,所以不需要再下傳取反標記了w;

最后,是老Re lz的代碼(是碼風清奇的奇女子將就着看叭):

Code:

#include<bits/stdc++.h>

using namespace std;

inline int read() {
	int ans=0;
	char last=' ',ch=getchar();
	while(ch>'9'||ch<'0') last=ch,ch=getchar();
	while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
	if(last=='-') ans=-ans;
	return ans;
}
const int mxn=200010;

int m,n,maxn;
int x[mxn];
struct node {
	int sum;
	int L[2],R[2];
	int qf,chg;
	int mx[2];
} t[mxn<<2];

void update(int k,int l,int r) {
	t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
	int mid=(l+r)>>1;
	for(int i=0; i<=1; i++) {
		t[k].L[i]=t[k<<1].L[i];
		if(t[k<<1].L[i]==mid-l+1)
			t[k].L[i]+=t[k<<1|1].L[i];

		t[k].R[i]=t[k<<1|1].R[i];
		if(t[k<<1|1].R[i]==r-mid)
			t[k].R[i]+=t[k<<1].R[i];

		t[k].mx[i]=max(t[k<<1].mx[i],max(t[k<<1|1].mx[i],t[k<<1].R[i]+t[k<<1|1].L[i]));
	}
}

void build(int k,int l,int r) {
	t[k].chg=-1;
	t[k].qf=0;
	if(l==r) {	
		t[k].L[0]=t[k].R[0]=t[k].mx[0]=x[l]==0;
		t[k].L[1]=t[k].R[1]=t[k].mx[1]=x[l]==1;
		if(x[l]) t[k].sum=1;
		return;
	}
	
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	update(k,l,r);
}

void pushdown(int k,int l,int r) {
	int mid=(l+r)>>1;
	if(t[k].chg!=-1) {
		int p=t[k].chg; 
		t[k].qf=0;
		t[k<<1].chg=t[k<<1|1].chg=p;
		t[k<<1].qf=t[k<<1|1].qf=0;
		t[k<<1].sum=(mid-l+1)*p;
		t[k<<1|1].sum=(r-mid)*p;
		t[k<<1].L[p]=t[k<<1].mx[p]=t[k<<1].R[p]=mid-l+1;
		t[k<<1|1].L[p]=t[k<<1|1].mx[p]=t[k<<1|1].R[p]=r-mid;
		t[k<<1].L[p^1]=t[k<<1].mx[p^1]=t[k<<1].R[p^1]=0;
		t[k<<1|1].L[p^1]=t[k<<1|1].mx[p^1]=t[k<<1|1].R[p^1]=0;
		t[k].chg=-1;
	}
	if(t[k].qf) {
		t[k<<1].sum=mid-l+1-t[k<<1].sum;
		t[k<<1|1].sum=r-mid-t[k<<1|1].sum;
		if(t[k<<1].chg!=-1) 
			t[k<<1].chg^=1;
		else 
			t[k<<1].qf^=1;
			
		if(t[k<<1|1].chg!=-1) 
			t[k<<1|1].chg^=1;
		else
			t[k<<1|1].qf^=1;
		swap(t[k<<1].L[0],t[k<<1].L[1]); 
		swap(t[k<<1].R[0],t[k<<1].R[1]);
		swap(t[k<<1].mx[0],t[k<<1].mx[1]);
		
		swap(t[k<<1|1].L[0],t[k<<1|1].L[1]);
		swap(t[k<<1|1].R[0],t[k<<1|1].R[1]);
		swap(t[k<<1|1].mx[0],t[k<<1|1].mx[1]);
		
		t[k].qf=0;
	}
}

void modify(int k,int l,int r,int x,int y,int q) {
	pushdown(k,l,r);
	if(x<=l&&r<=y) {
		if(q==1||q==0) {
			t[k].sum=(r-l+1)*q;
			t[k].L[q]=t[k].R[q]=t[k].mx[q]=r-l+1;
			t[k].L[q^1]=t[k].R[q^1]=t[k].mx[q^1]=0;
			t[k].chg=q;
		} else {
			t[k].sum=(r-l+1)-t[k].sum;
			t[k].qf^=1;
			swap(t[k].L[0],t[k].L[1]);
			swap(t[k].R[0],t[k].R[1]);
			swap(t[k].mx[0],t[k].mx[1]);
		}
		return;
	}
	
	int mid=(l+r)>>1;
	if(x<=mid) modify(k<<1,l,mid,x,y,q);
	if(y>mid) modify(k<<1|1,mid+1,r,x,y,q);
	update(k,l,r);
}

int query(int k,int l,int r,int x,int y) {
	pushdown(k,l,r);
	if(x<=l&&r<=y)
		return t[k].sum;
		
	int mid=(l+r)>>1;
	
	int rtn=0;
	if(x<=mid) rtn+=query(k<<1,l,mid,x,y);
	if(y>mid) rtn+=query(k<<1|1,mid+1,r,x,y);
	return rtn;
}

int Query(int k,int l,int r,int x,int y) {
	pushdown(k,l,r);
	if(x<=l&&r<=y) 
		return t[k].mx[1];
	int mid=(l+r)>>1;
	int rtn=0;
	if(x<=mid) rtn=max(rtn,Query(k<<1,l,mid,x,y));
	if(y>mid) rtn=max(rtn,Query(k<<1|1,mid+1,r,x,y));
	if(x<=mid&&y>mid) 
		rtn=max(rtn,min(mid-x+1,t[k<<1].R[1])+min(y-mid,t[k<<1|1].L[1]));
	return rtn;
}

int main() {
	n=read();
	m=read();
	for(int i=1; i<=n; i++) 
		x[i]=read();
	build(1,1,n);
	for(int i=1,op,a,b;i<=m;i++) {
		op=read();
		a=read();a++;
		b=read();b++;
		if(op==0)
			modify(1,1,n,a,b,0);
		if(op==1) 
			modify(1,1,n,a,b,1);
		if(op==2) 
			modify(1,1,n,a,b,2);
		if(op==3) 
			printf("%d\n",query(1,1,n,a,b));
		if(op==4) 
			printf("%d\n",Query(1,1,n,a,b));
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM