【線段樹】【P2572】【SCOI2010】序列操作
Description
lxhgww最近收到了一個01序列,序列裡面包含了n個數,這些數要麼是0,要麼是1,現在對於這個序列有五種變換操作和詢問操作:
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
對於每一種詢問操作,lxhgww都需要給出回答,聰明的程式設計師們,你們能幫助他嗎?
Input
輸入資料第一行包括2個數,n和m,分別表示序列的長度和運算元目
第二行包括n個數,表示序列的初始狀態
接下來m行,每行3個數,op, a, b,(0<=op<=4,0<=a<=b<n)表示對於區間[a, b]執行標號為op的操作
Output
對於每一個詢問操作,輸出一行,包括1個數,表示其對應的答案
Hint
對於30%的資料,1<=n, m<=1000
對於100%的資料,1<=n, m<=100000
Solution
測試題……睿智線段樹……頭一次寫多標記線段樹寫了7k然後爆10分……最後發現標記傳錯了……
考慮一個區間維護的資訊顯然有1的個數,連續1長度,左連續1,右連續1。0也同理。標記打上區間置零,賦一,取反。
考慮pushdown操作。
發現這三個標記只能同時存在一個,所以下傳的順序是無所謂的。但是需要考慮打標記的時候標記的重疊問題。具體的,在make_tag的時候,如果打賦1標記,若存在取反標記,則改為打賦0標記。同時把其餘標記置為false。區間置0同理。
考慮區間取反的時候,如果存在全部賦值標記,則將賦值標記取反,不打取反標記,否則將取反標記取反。因為把取反寫成賦true爆10分了……
大概就這樣
我好菜啊……寫了7k只有10分
Code
#include <cstdio> #include <iostream> #include <algorithm> #ifdef ONLINE_JUDGE #define freopen(a, b, c) #endif #define rg register #define ci const int #define cl const long long typedef long long int ll; namespace IPT { const int L = 1000000; char buf[L], *front=buf, *end=buf; char GetChar() { if (front == end) { end = buf + fread(front = buf, 1, L, stdin); if (front == end) return -1; } return *(front++); } } template <typename T> inline void qr(T &x) { rg char ch = IPT::GetChar(), lst = ' '; while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar(); while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar(); if (lst == '-') x = -x; } template <typename T> inline void ReadDb(T &x) { rg char ch = IPT::GetChar(), lst = ' '; while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar(); while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar(); if (ch == '.') { ch = IPT::GetChar(); double base = 1; while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar(); } if (lst == '-') x = -x; } namespace OPT { char buf[120]; } template <typename T> inline void qw(T x, const char aft, const bool pt) { if (x < 0) {x = -x, putchar('-');} rg int top=0; do {OPT::buf[++top] = x % 10 + '0';} while ( x /= 10); while (top) putchar(OPT::buf[top--]); if (pt) putchar(aft); } const int maxn = 100010; const int maxt = 200010; int n, m; int MU[maxn]; struct Tag { bool zero,one,bk; inline void clear() { zero = one = bk = false; } }; struct Info { int s0, s1, len0, len1, ll0, ll1, rl0, rl1; inline void buildit(int _v) { if (_v == 1) { len1 = ll1 = rl1 = s1 = 1; } else { len0 = ll0 = rl0 = s0 = 1; } } inline void clear() { s0 = s1 = len0 = len1 = ll0 = ll1 = rl0 = rl1 = 0; } inline Info operator+(const Info &_others) const { Info _ret; _ret.clear(); _ret.s0 = this->s0 + _others.s0; _ret.s1 = this->s1 + _others.s1; _ret.len0 = std::max(std::max(this->len0,_others.len0), this->rl0 + _others.ll0); _ret.len1 = std::max(std::max(this->len1,_others.len1), this->rl1 + _others.ll1); _ret.ll0 = this->ll0 + (!this->s1) * (_others.ll0); _ret.ll1 = this->ll1 + (!this->s0) * (_others.ll1); _ret.rl0 = _others.rl0 + (!_others.s1) * (this->rl0); _ret.rl1 = _others.rl1 + (!_others.s0) * (this->rl1); return _ret; } inline void reset(ci k) { if (k == 0) { this->s0 = this->ll0 = this->len0 = this->rl0 = this->s0 + this->s1; this->s1 = this->len1 = this->ll1 = this->rl1 = 0; } else if (k == 1) { this->s1 = this->ll1 = this->len1 = this->rl1 = this->s0 + this->s1; this->s0 = this->len0 = this->ll0 = this->rl0 = 0; } else { std::swap(this->s0,this->s1); std::swap(this->ll0,this->ll1); std::swap(this->len0,this->len1); std::swap(this->rl0,this->rl1); } } }; struct Tree { Tree *ls, *rs; int l, r; Tag tg; Info v; inline void pushup() { this->v.clear(); if((this->ls) && (!this->rs)) this->v = this->ls->v; else if((this->rs) && (!this->ls)) this->v = this->rs->v; else this->v = this->ls->v + this->rs->v; } inline void maketag(ci k) { if(k == 0) { this->tg.zero = true; this->v.reset(0); this->tg.one = this->tg.bk = false; } else if(k == 1) { this->tg.one = true; this->v.reset(1); this->tg.zero = this->tg.bk = false; } else { if(this->tg.one) { this->v.reset(0); std::swap(this->tg.one,this->tg.zero); } else if(this->tg.zero) { this->v.reset(1); std::swap(this->tg.one,this->tg.zero); } else { this->v.reset(2); this->tg.bk ^= 1; } } } inline void pushdown() { if (this->tg.zero) { if(this->ls) this->ls->maketag(0); if(this->rs) this->rs->maketag(0); } else if (this->tg.one) { if(this->ls) this->ls->maketag(1); if(this->rs) this->rs->maketag(1); } else if(this->tg.bk) { if(this->ls) this->ls->maketag(2); if(this->rs) this->rs->maketag(2); } this->tg.clear(); } }; Tree *pool[maxt], qwq[maxt], *rot; int top; struct Ret { int l,r,ans; bool isall; inline void clear() { l = r = ans = isall = 0; } }; void buildpool(); void buildroot(); void build(Tree*, ci, ci); void update(Tree*, ci, ci, ci); int ask3(Tree*, ci, ci); Ret ask4(Tree*, ci, ci); int main() { freopen("data.in", "r", stdin); qr(n); qr(m); for (rg int i = 1; i <= n; ++i) qr(MU[i]); buildpool(); buildroot(); build(rot, 1, n); int a, b, c; while (m--) { a = b = c = 0; qr(a); qr(b); qr(c); ++b;++c; switch(a) { case 0: { update(rot, b, c, 0); break; } case 1: { update(rot, b, c, 1); break; } case 2: { update(rot, b, c, 2); break; } case 3: { qw(ask3(rot, b, c), '\n', true); break; } case 4: { qw(ask4(rot, b, c).ans, '\n', true); break; } } } } void buildpool() { for (rg int i = 0; i < maxt; ++i) pool[i] = qwq+i; top = maxt - 1; } void buildroot() { rot = pool[top--]; rot->l = 1; rot->r = n; } void build(Tree *u, ci l, ci r) { if(l == r) {u->v.buildit(MU[l]); return;} int mid = (l + r) >> 1; if (l <= mid) { u->ls = pool[top--]; u->ls->l = l; u->ls->r = mid; build(u->ls, l, mid); } if(mid < r) { u->rs = pool[top--]; u->rs->l = mid+1; u->rs->r = r; build(u->rs, mid+1, r); } u->pushup(); } void update(Tree *u, ci l, ci r, ci v) { u->pushdown(); if((u->l >= l) && (u->r <= r)) { u->maketag(v);return; } if((u->l > r) || (u->r < l)) return; if(u->ls) update(u->ls, l, r, v); if(u->rs) update(u->rs, l, r, v); u->pushup(); } int ask3(Tree *u, ci l, ci r) { u->pushdown(); if((u->l >= l) && (u->r <= r)) return u->v.s1; else if((u->l > r) || (u->r < l)) return 0; int _ret = 0; if(u->ls) _ret = ask3(u->ls, l ,r); if(u->rs) _ret += ask3(u->rs, l, r); return _ret; } Ret ask4(Tree *u, ci l, ci r) { u->pushdown(); if((u->l >= l) && (u->r <= r)) { return (Ret){u->v.ll1, u->v.rl1, u->v.len1, u->v.s0 == 0}; } if((u->l > r) || (u->r < l)) { return (Ret){0, 0, 0, 0}; } Ret rl,rr,ret; rl.clear();rr.clear();ret.clear(); if(u->ls) rl = ask4(u->ls, l, r); if(u->rs) rr = ask4(u->rs, l, r); ret.l = rl.l + rl.isall * rr.l; ret.r = rr.r + rr.isall * rl.r; ret.ans = std::max(std::max(rl.ans, rr.ans), rl.r + rr.l); return ret; }
Summary
在多標記下傳時,考慮下傳順序間的影響,以及下傳新標記時,舊標記對新標記的影響。
另外比賽時如果正解寫掛一定要及時寫暴力……