1. 程式人生 > >luoguP2572 [SCOI2010]序列操作

luoguP2572 [SCOI2010]序列操作

... 標記 順序 wap \n inf name ios num

技術分享圖片

非常簡單的一道線段樹題

然而在考場上遇見還是打了$40min$,果然$gedit$不太適合我啊....

維護區間左端,右端,內部最長連續$0/ 1$,以及區間內$0 / 1$的個數即可回答

復雜度$O(n \log n)$

註:討論線段樹標記下放順序的時候,一定要有組樣例,腦想特別容易錯!

註2:反轉標記和覆蓋標記沒有絕對明顯的順序,可以根據實現決定誰先下放

#include <cstdio>
#include <iostream>
using namespace std;

#define gc getchar
inline int read() {
    
int p = 0, w = 1; char c = gc(); while(c > 9 || c < 0) { if(c == -) w = -1; c = gc(); } while(c >= 0 && c <= 9) p = p * 10 + c - 0, c = gc(); return p * w; } #define ri register int #define sid 600050 int n, m; int w[sid]; struct Seg { int lmax[2
], rmax[2], max[2], num[2]; int rev, cov, len; } t[sid]; #define ls (o << 1) #define rs (o << 1 | 1) void pcov(int o, int v) { t[o].lmax[v] = t[o].rmax[v] = t[o].max[v] = t[o].num[v] = t[o].len; t[o].rev = 0; t[o].cov = v; v ^= 1; t[o].lmax[v] = t[o].rmax[v] = t[o].max[v] = t[o].num[v] = 0
; } void prev(int o) { t[o].rev ^= 1; swap(t[o].lmax[1], t[o].lmax[0]); swap(t[o].rmax[1], t[o].rmax[0]); swap(t[o].max[1], t[o].max[0]); swap(t[o].num[1], t[o].num[0]); } void pud(int o) { if(t[o].cov != -1) { pcov(ls, t[o].cov); pcov(rs, t[o].cov); t[o].cov = -1; } if(t[o].rev) { prev(ls); prev(rs); t[o].rev = 0; } } void upd(int o) { for(ri i = 0; i <= 1; i ++) { t[o].lmax[i] = t[ls].lmax[i]; if(t[ls].num[i] == t[ls].len) t[o].lmax[i] = t[rs].lmax[i] + t[ls].len; t[o].rmax[i] = t[rs].rmax[i]; if(t[rs].num[i] == t[rs].len) t[o].rmax[i] = t[ls].rmax[i] + t[rs].len; t[o].max[i] = max(t[ls].rmax[i] + t[rs].lmax[i], max(t[rs].max[i], t[ls].max[i])); t[o].num[i] = t[ls].num[i] + t[rs].num[i]; } } void Init_Seg(int o, int l, int r) { t[o].len = r - l + 1; t[o].cov = -1; if(l == r) { int v = w[l]; t[o].lmax[v] = t[o].rmax[v] = 1; t[o].max[v] = t[o].num[v] = 1; return; } int mid = (l + r) >> 1; Init_Seg(ls, l, mid); Init_Seg(rs, mid + 1, r); upd(o); } void Cov(int o, int l, int r, int ml, int mr, int v) { if(ml > r || mr < l) return; if(ml <= l && mr >= r) { pcov(o, v); return; } pud(o); int mid = (l + r) >> 1; Cov(ls, l, mid, ml, mr, v); Cov(rs, mid + 1, r, ml, mr, v); upd(o); } void Rev(int o, int l, int r, int ml, int mr) { if(ml > r || mr < l) return; if(ml <= l && mr >= r) { prev(o); return; } pud(o); int mid = (l + r) >> 1; Rev(ls, l, mid, ml, mr); Rev(rs, mid + 1, r, ml, mr); upd(o); } int Sum(int o, int l, int r, int ml, int mr) { if(ml > r || mr < l) return 0; if(ml <= l && mr >= r) return t[o].num[1]; pud(o); int mid = (l + r) >> 1; return Sum(ls, l, mid, ml, mr) + Sum(rs, mid + 1, r, ml, mr); } int pre, ans; void Max(int o, int l, int r, int ml, int mr) { if(ml > r || mr < l) return; if(ml <= l && mr >= r) { ans = max(ans, t[o].max[1]); ans = max(ans, pre + t[o].lmax[1]); if(t[o].num[1] == t[o].len) pre += t[o].len; else pre = t[o].rmax[1]; return; } pud(o); int mid = (l + r) >> 1; Max(ls, l, mid, ml, mr); Max(rs, mid + 1, r, ml, mr); } int main() { n = read(); m = read(); for(ri i = 1; i <= n; i ++) w[i] = read(); Init_Seg(1, 1, n); for(ri i = 1; i <= m; i ++) { int opt = read(), l = read() + 1, r = read() + 1; if(opt == 0) Cov(1, 1, n, l, r, 0); if(opt == 1) Cov(1, 1, n, l, r, 1); if(opt == 2) Rev(1, 1, n, l, r); if(opt == 3) printf("%d\n", Sum(1, 1, n, l, r)); if(opt == 4) pre = 0, ans = 0, Max(1, 1, n, l, r), printf("%d\n", ans); } return 0; }

luoguP2572 [SCOI2010]序列操作