luoguP2572 [SCOI2010]序列操作
非常简单的一道线段树题
然而在考场上遇见还是打了$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; }
喵喵喵?喵喵喵! 喵喵喵......