题解 P2572 【[SCOI2010]序列操作】

SuperJvRuo

2018-10-03 19:14:10

Personal

三个月之前我第一次尝试这道题的时候,我写了将近4KB的线段树,WA得只有10分。 今天突然想起这道题,十几分钟就用[珂朵莉树](https://www.luogu.org/blog/ACdreamer/chtholly-tree)水过去了。当然由于这题数据不是随机的,珂朵莉树的复杂度是错的。五种操作中有两种是区间赋值,一种是反转,另外两种是查询。都可以用珂朵莉树```split```一波然后暴力搞定。 开O2之后475ms,速度和大多数线段树差不多吧。 ``` #include<cstdio> #include<cctype> #include<set> #include<vector> #include<utility> #include<algorithm> #define IT set<node>::iterator int Read() { int x=0;char c=getchar(); while(!isdigit(c)) { c=getchar(); } while(isdigit(c)) { x=x*10+(c^48); c=getchar(); } return x; } using std::set; using std::vector; using std::pair; typedef long long LL; const int MOD7 = 1e9 + 7; const int MOD9 = 1e9 + 9; const int imax_n = 1e5 + 7; struct node { int l,r; mutable bool v; node(int L, int R=-1, bool V=0):l(L), r(R), v(V) {} bool operator<(const node& o) const { return l < o.l; } }; set<node> s; //split(pos)操作是指将原来含有pos位置的节点分成两部分:[l,pos−1]和[pos,r] IT split(int pos) { IT it = s.lower_bound(node(pos)); if (it != s.end() && it->l == pos) return it; --it; int L = it->l, R = it->r; bool V = it->v; s.erase(it); s.insert(node(L, pos-1, V)); return s.insert(node(pos, R, V)).first; //这里利用了pair<iterator,bool> insert (const value_type& val)的返回值 } //ass♂ign操作迅速减小set的规模 void assign_val(int l, int r, bool val) { IT itr = split(r+1), itl = split(l); s.erase(itl, itr); //void erase (iterator first, iterator last)可删除[first,last)区间 s.insert(node(l, r, val)); } void rev(int l, int r) { IT itr = split(r+1), itl = split(l); for(; itl != itr; ++itl) { itl->v ^= 1; } } int sum(int l, int r) { IT itr = split(r+1),itl = split(l); int res = 0; for (; itl != itr; ++itl) res += itl->v ? itl->r - itl->l + 1 : 0; return res; } int conti(int l,int r) { int res=0,temp=0; IT itr = split(r+1),itl = split(l); for(; itl != itr; ++itl) { if(itl->v == false) { res = std::max(res, temp); temp=0; } else { temp += itl->r - itl->l + 1; } } return std::max(res, temp); } LL a[imax_n]; int main() { int n=Read(), m=Read(); for (int i=0; i<n; ++i) { s.insert(node(i,i,Read())); } s.insert(node(n, n, 0)); int op, a, b; for (int i =1; i <= m; ++i) { op=Read(), a=Read(), b=Read(); if(op == 0) { assign_val(a, b, 0); } else if(op == 1) { assign_val(a, b, 1); } else if(op == 2) { rev(a, b); } else if(op == 3) { printf("%d\n",sum(a, b)); } else { printf("%d\n",conti(a,b)); } } return 0; } ```