傻逼線段樹題,碼量第一次超 \(6.5k\)ios
由於不能考 \(NOIp\) 一氣之下把它肝了(放屁,你是由於想看小說,而作數據結構不用腦子,好在DJ來的時候方便掩飾數據結構
我的感受理解本題後會對線段樹有更爲深入的理解,亦可增長對線段樹的套路用法,瞭解各操做之間的優先級ui
本題解陳述儘可能詳細周全,如有贅述的地方請自行跳過,若是有什麼疑問也可在評論區提出spa
題面code
給定一段 \(01\) 序列,有 \(5\) 種操做get
0、一段區間變成 \(0\)
一、一段區間變成 \(1\)
二、對一段區間取反
三、詢問一段區間內有多少個 \(1\)
四、詢問一段區間內最多有多少個連續的 \(1\)string
序列長爲 \(n\) ,有 \(m\) 個操做(數據範圍:\(1 \le n,m\le 10^5\))it
操做 \(0,1,3\) 都比較好解決,線段樹基本操做,這裏不贅述io
主要是 \(2,4\) 操做class
對於 \(4\) 操做,咱們不難想到能夠用 \(max\) 維護區間最長的 \(1\) ,分別用 \(lmax\) 和 \(rmax\) 來維護左端點最長的 \(1\) 和右端點最長的 \(1\)
在上傳是注意 \(max\) 要和左右兒子的 \(max\) ,以及左兒子的 \(rmax\) 加右兒子的 \(lmax\) 這三個值中取最大值
(相信作過 GSS3 都能直接想到 \(4\) 的處理方法,沒作過也沒有關係,思路應該也是比較好理解的)
那加上 \(2\) 操做怎麼融合,另設一個懶標記 \(rev\) 來表示是否翻轉
一、由於有兩種修改操做,考慮懶標記優先級:由於 \(0, 1\) 的操做會把取反操做覆蓋掉,因此覆蓋的優先級要高於反轉的優先級
二、只有一個 \(max,lmax,rmax\),每次翻轉後怎麼更新:直接設兩個不就行了,把 \(0, 1\) 的 \(max, lmax, rmax\) 都存下來,翻轉的時候只要交換就行了
三、翻轉後如何求和:這個比較簡單,用長度減掉原來的 \(sum\) 就行了
在詢問 \(4\) 操做時,要注意兩端序列的合併應使用結構體回傳(好像較爲複雜的線段樹題都須要這樣處理)
由於最後的答案多是由兩段區間合併而成
因爲碼量較大,請注意保護眼睛
儘量的作到了排版整齊,變量名稱清新易懂,過程簡潔明瞭,還附有必定的註釋來幫助理解
能夠考慮用循環減小碼量,但我感受拆開寫更方便理解(善用位運算能夠省很多力)
(感謝_wzd提出在4操做中回傳有關0的 \(max,lmax,rmax\) 沒有意義,所以能夠省略)
/* Work by: Suzt_ilymics Knowledge: 傻逼線段樹 Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define lson i << 1 #define rson i << 1 | 1 #define orz cout<<"lkp ak ioi"<<endl; using namespace std; const int MAXN = 1e5+5; const int INF = 1; const int mod = 1; struct Tree{ int len, lazy, sum, lmax[2], rmax[2], max[2], rev; }tree[MAXN << 2]; int n, m; int a[MAXN]; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } int max(int x, int y){ return x > y ? x : y; } void push_up(int i){//上傳 tree[i].sum = tree[lson].sum + tree[rson].sum;//維護區間和 if(tree[lson].sum == tree[lson].len) tree[i].lmax[1] = tree[lson].lmax[1] + tree[rson].lmax[1];//維護 else tree[i].lmax[1] = tree[lson].lmax[1]; if(tree[rson].sum == tree[rson].len) tree[i].rmax[1] = tree[rson].rmax[1] + tree[lson].rmax[1]; else tree[i].rmax[1] = tree[rson].rmax[1]; tree[i].max[1] = max(tree[lson].max[1], tree[rson].max[1]);//維護區間最多有的連續的1,取左區間最大值、右區間最大值、左區間右邊最大值和右區間左邊最大值的和三個中的最大值 tree[i].max[1] = max(tree[i].max[1], tree[lson].rmax[1] + tree[rson].lmax[1]); if(tree[lson].sum == 0) tree[i].lmax[0] = tree[lson].lmax[0] + tree[rson].lmax[0];//維護 else tree[i].lmax[0] = tree[lson].lmax[0]; if(tree[rson].sum == 0) tree[i].rmax[0] = tree[rson].rmax[0] + tree[lson].rmax[0]; else tree[i].rmax[0] = tree[rson].rmax[0]; tree[i].max[0] = max(tree[lson].max[0], tree[rson].max[0]);//維護區間最多有的連續的0,取左區間最大值、右區間最大值、左區間右邊最大值和右區間左邊最大值的和三個中的最大值 tree[i].max[0] = max(tree[i].max[0], tree[lson].rmax[0] + tree[rson].lmax[0]); return ; } void build(int i, int l, int r){ tree[i].len = r - l + 1, tree[i].lazy = -1, tree[i].rev = 0; if(l == r) { tree[i].sum = a[l]; tree[i].max[0] = tree[i].lmax[0] = tree[i].rmax[0] = (a[l] == 0); tree[i].max[1] = tree[i].lmax[1] = tree[i].rmax[1] = (a[l] == 1); return ; } int mid = (l + r) >> 1; build(lson, l, mid), build(rson, mid + 1, r); push_up(i); return ; } void push_down(int i){//下穿,注意優先級 if(tree[i].lazy != -1){ tree[i].rev = 0; int val = tree[i].lazy; tree[lson].sum = tree[lson].len * val; tree[rson].sum = tree[rson].len * val; tree[lson].lazy = tree[rson].lazy = val; tree[lson].rev = tree[rson].rev = 0; tree[lson].lmax[val ^ 1] = tree[lson].rmax[val ^ 1] = tree[lson].max[val ^ 1] = 0; tree[rson].lmax[val ^ 1] = tree[rson].rmax[val ^ 1] = tree[rson].max[val ^ 1] = 0; tree[lson].lmax[val] = tree[lson].rmax[val] = tree[lson].max[val] = tree[lson].len; tree[rson].lmax[val] = tree[rson].rmax[val] = tree[rson].max[val] = tree[rson].len; tree[i].lazy = -1; } if(tree[i].rev){ tree[lson].sum = tree[lson].len - tree[lson].sum; tree[rson].sum = tree[rson].len - tree[rson].sum; if(tree[lson].lazy != -1) tree[lson].lazy ^= 1; else tree[lson].rev ^= 1; if(tree[rson].lazy != -1) tree[rson].lazy ^= 1; else tree[rson].rev ^= 1; swap(tree[lson].max[0], tree[lson].max[1]); swap(tree[lson].lmax[0], tree[lson].lmax[1]); swap(tree[lson].rmax[0], tree[lson].rmax[1]); swap(tree[rson].max[0], tree[rson].max[1]); swap(tree[rson].lmax[0], tree[rson].lmax[1]); swap(tree[rson].rmax[0], tree[rson].rmax[1]); tree[i].rev = 0; } return ; } void change01(int i, int l, int r, int L, int R, int k){//01覆蓋操做 push_down(i); if(L <= l && r <= R){ tree[i].sum = tree[i].len * k; tree[i].lazy = k; tree[i].lmax[k] = tree[i].rmax[k] = tree[i].max[k] = tree[i].len; tree[i].lmax[k ^ 1] = tree[i].rmax[k ^ 1] = tree[i].max[k ^ 1] = 0; return ; } int mid = (l + r) >> 1; if(mid < L) change01(rson, mid + 1, r, L, R, k); else if(mid >= R) change01(lson, l, mid, L, R, k); else change01(lson, l, mid, L, mid, k), change01(rson, mid + 1, r, mid + 1, R, k); push_up(i); } void changef(int i, int l, int r, int L, int R){//取反操做 push_down(i); if(L <= l && r <= R){ tree[i].sum = tree[i].len - tree[i].sum; tree[i].rev ^= 1; swap(tree[i].max[1], tree[i].max[0]); swap(tree[i].lmax[1], tree[i].lmax[0]); swap(tree[i].rmax[1], tree[i].rmax[0]); return ; } int mid = (l + r) >> 1; if(mid < L) changef(rson, mid + 1, r, L, R); else if(mid >= R) changef(lson, l, mid, L, R); else changef(lson, l, mid, L, mid), changef(rson, mid + 1, r, mid + 1, R); push_up(i); } int get_sum(int i, int l, int r, int L, int R){//區間和 push_down(i); if(L <= l && r <= R){ return tree[i].sum; } int mid = (l + r) >> 1, ans = 0; if(mid < L) return get_sum(rson, mid + 1, r, L, R); else if(mid >= R) return get_sum(lson, l, mid, L, R); else return get_sum(lson, l, mid, L, mid) + get_sum(rson, mid + 1, r, mid + 1, R); } Tree get_max(int i, int l, int r, int L, int R){//區間最大值 // cout<<i<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<endl; push_down(i); if(L <= l && r <= R){ return tree[i]; } int mid = (l + r)>> 1; if(mid < L) return get_max(rson, mid + 1, r, L, R); else if(mid >= R) return get_max(lson, l, mid, L, R); else { Tree ans, ansl = get_max(lson, l, mid, L, mid), ansr = get_max(rson, mid + 1, r, mid + 1, R); ans.sum = ansl.sum + ansr.sum; ans.lmax[1] = ansl.lmax[1], ans.lmax[0] = ansl.lmax[0]; if(ansl.sum == ansl.len) ans.lmax[1] += ansr.lmax[1]; if(ansl.sum == 0) ans.lmax[0] += ansr.lmax[0]; ans.rmax[1] = ansr.rmax[1], ans.rmax[0] = ansr.rmax[0]; if(ansr.sum == ansr.len) ans.rmax[1] += ansl.rmax[1]; if(ansr.sum == 0) ans.rmax[0] += ansl.rmax[0]; ans.max[1] = max(ansl.max[1], ansr.max[1]); ans.max[1] = max(ans.max[1], ansl.rmax[1] + ansr.lmax[1]); ans.max[0] = max(ansl.max[0], ansr.max[0]); ans.max[0] = max(ans.max[0], ansl.rmax[0] + ansr.lmax[0]); return ans; } } int main() { n = read(), m = read(); for(int i = 1; i <= n; ++i) a[i] = read(); build(1, 1, n); for(int i = 1, opt, l, r; i <= m; ++i){ opt = read(), l = read() + 1, r = read() + 1; if(opt == 0){ change01(1, 1, n, l, r, 0); } if(opt == 1){ change01(1, 1, n, l, r, 1); } if(opt == 2){ changef(1, 1, n, l, r); } if(opt == 3){ printf("%d\n", get_sum(1, 1, n, l, r)); } if(opt == 4){ printf("%d\n", get_max(1, 1, n, l, r).max[1]); } } return 0; }