hdu 3911-區間合併、更新和查詢Black And White (&& hdu 1199)
阿新 • • 發佈:2019-02-14
一個序列要麼是1,要麼是0.
操作:
修改:修改區間[a,b],使0變成1,1變成0;
詢問:區間[a,b]最長的連續1有多長?
解:
線段樹。
節點資訊:
preb,sufb,prew,sufw,mxb,mxw;分別表示最長1字首,最長1字尾,最長0字首,最長0字尾,本區間最長1,本區間最長0.
之所以這麼多個東西,是為了修改的時候方便。只要將帶0的和帶1的換一下就好了。
更新的時候不要更新到底,需要lazy操作。
詢問的時候和push_up的時候,需要將情況考慮周全。
做的時候的問題:
更新的時候腫麼辦呢?不能由根再更新葉子啊。-------原來就是一個lazy操作,就是要更新到葉子,用lazy優化。
之前想的節點少了幾個字首和字尾,然後沒想通更新的時候腫麼更新。
查詢的時候必須是三段式的。當查詢區間在m左右兩端的時候,最長可能只在m左邊,可能只在m右邊,可能包括m。這些都是不能落掉的。
WA了n次之後覺得,應該是一個細節問題沒有處理好。
A之後:
又WA了有個把小時。關鍵在於細節。剛開始是真的有些問題沒考慮到或者考慮錯了(比如query那裡和最長子串的維護),但是後面之所以錯就是細節。把原本寫好的col[] = 0給刪了,這樣導致每次用的lazy標記混亂。還有就是把sufw寫成了sufb,這可完全是細節問題啊!!!不過心裡暗示挺重要的,知道是細節問題之後我就寫註釋什麼的,找出來只花了十幾分鍾。
/* Pro: 0 Sol: date: */ #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <set> #include <vector> #define maxn 111111 #define lson l, m , rt << 1 #define rson m + 1, r,rt << 1 | 1 #define ls (rt << 1) #define rs (rt << 1 | 1) #define havem int m = (l + r) >> 1 using namespace std; int n,Q,ax; int preb[maxn << 2],sufb[maxn << 2],mxb[maxn << 2]; int prew[maxn << 2],sufw[maxn << 2],mxw[maxn << 2],col[maxn << 2]; int num[maxn]; inline int max(int a, int b) {return a > b? a: b;} inline int min(int a, int b) {return a < b? a: b;} void push_up(int rt,int m){ //維護字首 preb[rt] = preb[ls];//先等於左孩子的字首 prew[rt] = prew[ls]; if(preb[ls] == m - (m >> 1)) preb[rt] += preb[rs];//如果左孩子的字首長度等於左孩子區間長度, if(prew[ls] == m - (m >> 1)) prew[rt] += prew[rs];//那麼,加上右孩子的字首 //維護字尾 sufb[rt] = sufb[rs];//先等於右孩子的字尾 sufw[rt] = sufw[rs];//我勒個去,就是這裡寫成sufb了,WA了n次啊。。。 if(sufb[rs] == (m >> 1)) sufb[rt] += sufb[ls];//如果右孩子的字尾長度等於右孩子區間長度 if(sufw[rs] == (m >> 1)) sufw[rt] += sufw[ls];//那麼,加上左孩子的字尾 //維護本區間最長的長串 mxb[rt] = max(mxb[ls],mxb[rs]);//這裡也錯了。 mxb[rt] = max(mxb[rt], sufb[ls] + preb[rs]); mxw[rt] = max(mxw[ls],mxw[rs]);//最長串要不單獨在左孩子,要不在右孩子 mxw[rt] = max(mxw[rt], sufw[ls] + prew[rs]);//要不同時分佈在左孩子、右孩子 } inline void exchange(int rt){//交換 swap(preb[rt],prew[rt]); swap(sufb[rt],sufw[rt]); swap(mxb[rt],mxw[rt]); } void push_dn(int rt){ if(col[rt]){ col[ls] ^= 1, col[rs] ^= 1, col[rt] = 0; exchange(ls); exchange(rs);//這裡錯了 } } void build(int l, int r, int rt){ col[rt] = 0; if(l == r){ scanf("%d",&ax); if(ax == 1){//如果是黑色的 preb[rt] = sufb[rt] = mxb[rt] = 1; prew[rt] = sufw[rt] = mxw[rt] = 0; }else{//如果是白色的 preb[rt] = sufb[rt] = mxb[rt] = 0; prew[rt] = sufw[rt] = mxw[rt] = 1; } return ; }havem; build(lson); build(rson); push_up(rt,r - l + 1); } void update(int& L, int& R, int l, int r, int rt){//區間更新 if(L <= l && r <= R){ col[rt] ^= 1; exchange(rt);//改變自身之後,改變lazy標誌 return ; }push_dn(rt); havem; if(L <= m) update(L,R,lson); if(R > m) update(L,R,rson); push_up(rt,r - l + 1); } int query(int& L, int& R, int l, int r, int rt){ if(L <= l && r <= R) return mxb[rt]; push_dn(rt); havem; if(L > m) return query(L,R,rson); if(R <= m) return query(L,R,lson); int t1 = query(L,R,lson); int t2 = query(L, R, rson); int wa1 = min(m - L + 1, sufb[ls]);//這裡又錯了兩次m - L 才對,我寫成L - m了 int wa2 = min(R - m, preb[rs]);//應該取一個最小值才行。 return max(max(t1,t2),wa1 + wa2); } int main(){ int op,a,b; while(scanf("%d",&n) != EOF){ build(1,n,1); scanf("%d",&Q); for(int i = 1;i <= Q; i ++){ scanf("%d%d%d",&op,&a,&b); if(op == 1){ update(a,b,1,n,1); }else{ int ans = query(a,b,1,n,1); printf("%d\n",ans); } } } return 0; }