P2572 序列操作

P2572 序列操作

问题

P2572 [SCOI2010] 序列操作
维护一个 01 序列,支持区间全部改为零、全部改为一、整体翻转,并询问区间内一的数量或最长连续一段。

数据规模:n,m≤105n,m\le 10^5,题目下标从零开始。

这题其实像前面几题的组装版:P2574 的区间翻转、P1253 的标记复合,以及 P6492 STEP 的信息合并。

回到本题,区间和只能回答一的数量,要询问最长连续一,还得同时维护 00 和 11 各自的最长前缀、后缀与区间答案。

不然由于区间会翻转或者覆盖,没法直接维护前缀 1 和 后缀 1 的数量,所以还需要跟 前缀 0 和 后缀 0 打配合。

然后就是类似的合并了,主要是写起来很麻烦。

覆盖 0 或 1 时重置翻转;翻转时交换 0/1 的全部统计,已有覆盖就翻转覆盖值,否则异或累计翻转,下传顺序保持先覆盖、后翻转。查询最长一段时应直接取返回节点的 mx[1]。

一道很综合的线段树题,这才青题吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
struct SegTree {
/* ================================================== */
struct Node {
int l, r;
int sum, cov, rev;
int lmx[2], rmx[2], mx[2];
} tr[maxn << 2];

int len( int u ) {
return tr[u].r - tr[u].l + 1;
}

void push_up( int u ) {
tr[u].sum = tr[ls].sum + tr[rs].sum;

for( int c = 0; c <= 1; ++ c ) {
tr[u].lmx[c] = tr[ls].lmx[c];
if( tr[ls].lmx[c] == len( ls ) ) {
tr[u].lmx[c] += tr[rs].lmx[c];
}
tr[u].rmx[c] = tr[rs].rmx[c];
if( tr[rs].rmx[c] == len( rs ) ) {
tr[u].rmx[c] += tr[ls].rmx[c];
}
tr[u].mx[c] = max({
tr[ls].mx[c], tr[rs].mx[c],
tr[ls].rmx[c] + tr[rs].lmx[c]
});
}
}

void apply_rev( int u ) {
tr[u].sum = len( u ) - tr[u].sum;
swap( tr[u].lmx[0], tr[u].lmx[1] );
swap( tr[u].rmx[0], tr[u].rmx[1] );
swap( tr[u].mx[0], tr[u].mx[1] );
if( tr[u].cov != -1 ) tr[u].cov ^= 1;
else tr[u].rev ^= 1;
}

void apply_cov( int u, int val ) {
tr[u].sum = val ? len( u ) : 0;
tr[u].lmx[0] = tr[u].rmx[0] = tr[u].mx[0] = val == 0 ? len( u ) : 0;
tr[u].lmx[1] = tr[u].rmx[1] = tr[u].mx[1] = val == 1 ? len( u ) : 0;
tr[u].cov = val;
tr[u].rev = 0;
}

void push_down( int u ) {
if( tr[u].cov != -1 ) {
apply_cov( ls, tr[u].cov );
apply_cov( rs, tr[u].cov );
tr[u].cov = -1;
}
if( tr[u].rev ) {
apply_rev( ls );
apply_rev( rs );
tr[u].rev = 0;
}
}

void build( int u, int l, int r, ll val[] ) {
tr[u] = { l, r, 0, -1, 0 };
if( l == r ) {
int c = val[l];
int d = c ^ 1;
tr[u].sum = c;
tr[u].lmx[c] = tr[u].rmx[c] = tr[u].mx[c] = 1;
tr[u].lmx[d] = tr[u].rmx[d] = tr[u].mx[d] = 0;
return ;
}
int mid = ( l + r ) >> 1;
build( ls, l, mid, val );
build( rs, mid + 1, r, val );
push_up( u );
}

void upd( int u, int l, int r, int opt ) {
if( l <= tr[u].l && tr[u].r <= r ) {
if( opt == 0 || opt == 1 ) apply_cov( u, opt );
else apply_rev( u );
return ;
}
push_down( u );
int mid = ( tr[u].l + tr[u].r ) >> 1;
if( l <= mid ) upd( ls, l, r, opt );
if( mid < r ) upd( rs, l, r, opt );
push_up( u );
}

Node merge( Node L, Node R ) {
Node res = { L.l, R.r, L.sum + R.sum, -1, 0 };
int lenL = L.r - L.l + 1;
int lenR = R.r - R.l + 1;
for( int c = 0; c <= 1; ++ c ) {
res.lmx[c] = L.lmx[c];
if( L.lmx[c] == lenL ) {
res.lmx[c] += R.lmx[c];
}
res.rmx[c] = R.rmx[c];
if( R.rmx[c] == lenR ) {
res.rmx[c] += L.rmx[c];
}
res.mx[c] = max({
L.mx[c], R.mx[c],
L.rmx[c] + R.lmx[c]
});
}
return res;
}

Node ask( int u, int l, int r ) {
if( l <= tr[u].l && tr[u].r <= r ) return tr[u];
push_down( u );
int mid = ( tr[u].l + tr[u].r ) >> 1;
if( r <= mid ) return ask( ls, l, r );
if( mid < l ) return ask( rs, l, r );
return merge( ask( ls, l, r ), ask( rs, l, r ) );
}
/* ================================================== */
} seg;

ll a[maxn];

void solve( ) {
int n = read( ), m = read( );
for( int i = 1; i <= n; ++ i ) a[i] = read( );
seg.build( 1, 1, n, a );

for( int i = 1; i <= m; ++ i ) {
int opt = read( );
int l = read( ) + 1, r = read( ) + 1;
if( opt == 0 || opt == 1 || opt == 2 ) {
seg.upd( 1, l, r, opt );
}
else if( opt == 3 ) {
cout << seg.ask( 1, l, r ).sum << '\n';
}
else {
cout << seg.ask( 1, l, r ).mx[1] << '\n';
}
}
}

记录

  • 归属:线段树信息合并、浅谈线段树懒标记。
  • 新增:为了同时支持翻转和连续段查询,节点应对称维护零和一的信息,标记应按操作函数的真实复合关系更新。
  • 分类:保留;承担 Info × Tag 的完整交叉案例。

P2572 序列操作
http://miqiu.space/posts/p2572001/
作者
Miqiu
发布于
2026年8月12日
许可协议