【BZOJ1858】【SCOI2010】序列操作 线段树
好累啊,不想写题解了,直接发别人的了。
By:smallling
这题我很二的折腾了一下午,唉,还是太弱了。这题的关键在于标记的更新与更新每个点的权值,更新标记我很快就写好了,思路很清晰,但是查找答案就头晕了,在处理下传标记、更新权值中纠结。。。。
这题我用sum来记录一段区间内1的个数,lseg记录该区间从左往右连续的1的个数,rseg记录该区间从右往左连续的1的个数,seg记录记录该区间中最长的连续1的长度。0同理用另一个数组记录。
下面考虑两个区间的合并,1的个数的合并很简单,直接将权值累加即可。最长连续的1的个数就有点麻烦了,一种情况就是直接从两个区间的seg的最大值继承过来,但这不一定是最优的,因为还有一种可能,就是左边区间的rseg+右边区间的lseg,这可能比之前的最大值更优。lseg的值可以先从左边区间的lest继承过来,如果左边区间的lseg=左边区间的总长度,说明当前区间的lseg还能扩展到右边区间,那么只要左边区间的lseg+右边区间的lseg即可。处理rseg反向考虑一下即可。
接下来考虑修改操作的合并,不难发现覆盖操作的优先级比取反高,因此如果当前操作是覆盖,直接覆盖之前的操作即可。如果是取反,那么也很好想,用1覆盖后在取反,不就是用0覆盖,用0覆盖后取反,就是用1覆盖,取反后再取反,就相当于没有取反~~lazy标记同理即可~是不是很简单
再接下来我们考虑对于每个记录我们该如何操作。也许你会问之前记录0是干嘛的,在这里就要发挥用处啦。如果当前是用1或0全部覆盖,那么把1或0的sum,lseg,rseg,seg全部赋为当前区间的长度即可。如果是取反,就是把0的信息给1,1的信息给0,直接交换0,1的sum,lseg,rseg,seg,是不是也很简单~~~~
之后就是坑爹的ADD和ASK了。。这个大家不同的线段树有不同的写法,我也不详说,注意一下下传标记和区间信息的更新。。还有就是求最长连续1的时候,左右合并要注意长度不能大于当前mid-l+1和r-mid。
原文地址:http://www.cnblogs.com/smallling/p/3695072.html。
代码是自己的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 6 using namespace std; 7 8 const int N = 400000 + 5; 9 10 namespace SGT{ 11 #define lson rt<<1,l,mid 12 #define rson rt<<1|1,mid+1,r 13 int sum[N]; 14 int lseg[N][2], rseg[N][2], seg[N][2]; 15 int same[N], rev[N]; 16 void pushup( int rt, int len1, int len2 ){ 17 int ls = rt<<1, rs = rt<<1|1; 18 sum[rt] = sum[ls]+sum[rs]; 19 for ( int i = 0; i < 2; i ++ ){ 20 seg[rt][i] = max(seg[ls][i],seg[rs][i]); 21 seg[rt][i] = max(seg[rt][i],rseg[ls][i]+lseg[rs][i]); 22 lseg[rt][i] = lseg[ls][i]; 23 rseg[rt][i] = rseg[rs][i]; 24 if ( sum[ls] == len1*i ) lseg[rt][i] += lseg[rs][i]; 25 if ( sum[rs] == len2*i ) rseg[rt][i] += rseg[ls][i]; 26 } 27 } 28 void set_same( int rt, int u, int len ){ 29 int v = !u; 30 same[rt] = u, rev[rt] = 0; 31 sum[rt] = u*len; 32 seg[rt][u] = lseg[rt][u] = rseg[rt][u] = len; 33 seg[rt][v] = lseg[rt][v] = rseg[rt][v] = 0; 34 } 35 void set_rev( int rt, int len ){ 36 if ( same[rt] == -1 ){ 37 rev[rt] ^= 1; 38 sum[rt] = len-sum[rt]; 39 swap(seg[rt][0],seg[rt][1]); 40 swap(lseg[rt][0],lseg[rt][1]); 41 swap(rseg[rt][0],rseg[rt][1]); 42 }else set_same(rt,!same[rt],len); 43 } 44 void pushdown( int rt, int l, int r ){ 45 int ls = rt<<1, rs = rt<<1|1; 46 int mid = (l + r) >> 1; 47 if ( same[rt] != -1 ){ 48 set_same(ls,same[rt],mid-l+1); 49 set_same(rs,same[rt],r-mid); 50 same[rt] = -1; 51 } 52 if ( rev[rt] ){ 53 set_rev(ls,mid-l+1); 54 set_rev(rs,r-mid); 55 rev[rt] = 0; 56 } 57 } 58 void build( int rt, int l, int r ){ 59 same[rt] = -1; 60 if ( l == r ){ 61 scanf( "%d", &sum[rt] ); 62 int w = sum[rt]; 63 seg[rt][w] = lseg[rt][w] = rseg[rt][w] = 1; 64 return; 65 } 66 int mid = (l + r) >> 1; 67 build(lson), build(rson); 68 pushup(rt,mid-l+1,r-mid); 69 } 70 void update( int rt, int l, int r, int ql, int qr, int type ){ 71 if ( ql <= l && r <= qr ){ 72 if ( type <= 1 ) set_same(rt,type,r-l+1); 73 else set_rev(rt,r-l+1); 74 return; 75 } 76 pushdown(rt,l,r); 77 int mid = (l + r) >> 1; 78 if ( ql <= mid ) update(lson,ql,qr,type); 79 if ( qr > mid ) update(rson,ql,qr,type); 80 pushup(rt,mid-l+1,r-mid); 81 } 82 int qsum( int rt, int l, int r, int ql, int qr ){ 83 if ( ql <= l && r <= qr ) return sum[rt]; 84 pushdown(rt,l,r); 85 int mid = (l + r) >> 1, ret = 0; 86 if ( ql <= mid ) ret += qsum(lson,ql,qr); 87 if ( qr > mid ) ret += qsum(rson,ql,qr); 88 return ret; 89 } 90 struct Node{ 91 int l, r, w; 92 Node( int l=0, int r=0, int w=0 ):l(l),r(r),w(w){} 93 }; 94 Node qseg( int rt, int l, int r, int ql, int qr ){ 95 if ( l == ql && r == qr ) return Node(lseg[rt][1],rseg[rt][1],seg[rt][1]); 96 pushdown(rt,l,r); 97 int mid = (l + r) >> 1; 98 if ( qr <= mid ) return qseg(lson,ql,qr); 99 if ( ql > mid ) return qseg(rson,ql,qr); 100 Node t1 = qseg(lson,ql,mid), t2 = qseg(rson,mid+1,qr), t; 101 if ( t1.l == mid-l+1 ) t.l = t1.l+t2.l;else t.l = t1.l; 102 if ( t2.r == r - mid ) t.r = t1.r+t2.r;else t.r = t2.r; 103 t.w = max(max(t1.w,t2.w),t1.r+t2.l); 104 return t; 105 } 106 } 107 int n, m, t, x, y; 108 int main(){ 109 scanf( "%d%d", &n, &m ); 110 SGT::build(1, 1, n); 111 112 while ( m -- ){ 113 scanf( "%d%d%d", &t, &x, &y );++x, ++y; 114 if ( t <= 2 ) SGT::update(1,1,n,x,y,t); 115 if ( t == 3 ) printf( "%d\n", SGT::qsum(1,1,n,x,y) ); 116 if ( t == 4 ) printf( "%d\n", SGT::qseg(1,1,n,x,y).w ); 117 } 118 return 0; 119 }