Steven_MengのBlog

洛谷

BZOJ

线段树维护,每个节点上面记录$6$个值$l0,l1,r0,r1,m0,m1$(套路),代表从左开始最长$0$的序列长度,最长$1$的序列的长度,从右开始的……,中间的……(懒)

翻转就是把他们两两交换,$\rm pushup$也都是套路。

注意覆盖标记比翻转标记优先级高,于是区间覆盖的时候会把翻转标记设成$0$,$\rm pushdown$的时候也是先判断区间覆盖标记。

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
144
#include <bits/stdc++.h>
#define MAXN 100005
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+(ch^'0');
ch=getchar();
}
return x*f;
}
int a[MAXN];
namespace SegmentTree{
struct node{
int l,r;
int l0,r0,l1,r1,m0,m1;
int sum,tag;
bool rev;
inline int len(){return r-l+1;}
}tree[MAXN<<2];
#define lc i<<1
#define rc i<<1|1
inline void Rev(int i){
tree[i].sum=tree[i].len()-tree[i].sum;
swap(tree[i].l0,tree[i].l1);
swap(tree[i].r0,tree[i].r1);
swap(tree[i].m0,tree[i].m1);
tree[i].rev^=1;
}
inline void Cover(int i,int val){
tree[i].tag=val;
tree[i].sum=val*tree[i].len();
tree[i].l0=tree[i].r0=tree[i].m0=(1-val)*tree[i].len();
tree[i].r1=tree[i].l1=tree[i].m1=val*tree[i].len();
tree[i].rev=0;
}
inline void pushdown(int i){
if (tree[i].l==tree[i].r) return ;
if (tree[i].tag!=-1){
Cover(lc,tree[i].tag),Cover(rc,tree[i].tag);
tree[i].tag=-1;
}
if (tree[i].rev){
Rev(lc),Rev(rc);
tree[i].rev=0;
}
}
node operator + (node a,node b){
node c;
c.l=a.l,c.r=b.r;
c.l0=a.l0;
if (a.sum==0) c.l0=max(c.l0,a.len()+b.l0);
c.l1=a.l1;
if (a.sum==a.len()) c.l1=max(c.l1,a.len()+b.l1);
c.r0=b.r0;
if (b.sum==0) c.r0=max(c.r0,b.len()+a.r0);
c.r1=b.r1;
if (b.sum==b.len()) c.r1=max(c.r1,b.len()+a.r1);
c.m0=max(max(a.m0,b.m0),a.r0+b.l0);
c.m1=max(max(a.m1,b.m1),a.r1+b.l1);
c.sum=a.sum+b.sum;
return c;
}
inline void pushup(int i){
int temp1=tree[i].rev,temp2=tree[i].tag;
tree[i]=tree[lc]+tree[rc];
tree[i].rev=temp1,tree[i].tag=temp2;
}
void Build(int i,int l,int r){
tree[i].l=l,tree[i].r=r;
tree[i].tag=-1;
if (l==r){
Cover(i,a[l]);
return ;
}
int mid=(l+r)>>1;
Build(lc,l,mid);
Build(rc,mid+1,r);
pushup(i);
}
void Update(int i,int L,int R,int val){
if (L<=tree[i].l&&tree[i].r<=R){
Cover(i,val);
return ;
}
int mid=(tree[i].l+tree[i].r)>>1;
pushdown(i);
if (L<=mid) Update(lc,L,R,val);
if (mid<R) Update(rc,L,R,val);
pushup(i);
}
void Reverse(int i,int L,int R){
if (L<=tree[i].l&&tree[i].r<=R){
Rev(i);
return ;
}
int mid=(tree[i].l+tree[i].r)>>1;
pushdown(i);
if (L<=mid) Reverse(lc,L,R);
if (mid<R) Reverse(rc,L,R);
pushup(i);
}
int QuerySum(int i,int L,int R){
if (L<=tree[i].l&&tree[i].r<=R){
return tree[i].sum;
}
int mid=(tree[i].l+tree[i].r)>>1,ans=0;
pushdown(i);
if (L<=mid) ans+=QuerySum(lc,L,R);
if (mid<R) ans+=QuerySum(rc,L,R);
return ans;
}
node QueryMax(int i,int L,int R){
if (L<=tree[i].l&&tree[i].r<=R){
return tree[i];
}
int mid=(tree[i].l+tree[i].r)>>1;
pushdown(i);
if (mid>=R) return QueryMax(lc,L,R);
else if (L>mid) return QueryMax(rc,L,R);
else return QueryMax(lc,L,R)+QueryMax(rc,L,R);
}
}
using namespace SegmentTree;
int main(){
int n=read(),m=read();
for (register int i=1;i<=n;++i){
a[i]=read();
}
Build(1,1,n);
while (m--){
int opr=read(),l=read()+1,r=read()+1;
if (opr==0) Update(1,l,r,0);
if (opr==1) Update(1,l,r,1);
if (opr==2) Reverse(1,l,r);
if (opr==3) printf("%d\n",QuerySum(1,l,r));
if (opr==4) printf("%d\n",QueryMax(1,l,r).m1);
}
}

 评论