1 #include <bits/stdc++.h>
2 using namespace std;
3 const int maxn = 1e6+5;
4 struct node {
5 /// l,r表示当前结点区间范围[l,r]
6 int l, r;
7 /// val=0时为全0标志,表示区间[l,r]的值全为0
8 /// val=1时为全1标志,表示区间[l,r]的值全为1
9 /// val=-1时则代表无操作
10 /// xor为异或标志,表示区间[l,r]的值取异或操作
11 int val, Xor;
12 /// lmax_0表示区间[l,r]从左往右开始连续0的个数
13 /// rmax_0表示区间[l,r]从右往左开始连续0的个数
14 /// max_0表示当前区间最大连续0的个数
15 int lmax_0, rmax_0, max_0, sum_0;
16 int lmax_1, rmax_1, max_1, sum_1;
17 /// 得到当前区间长度
18 int len() { return r-l+1; }
19
20 /// 更新操作,val_代表01操作,xor_代表异或操作
21 void change(int val_, int Xor_) {
22 /// [l,r]全置为0
23 if (val_ == 0) {
24 lmax_0 = rmax_0 = max_0 = sum_0 = len();
25 lmax_1 = rmax_1 = max_1 = sum_1 = 0;
26 val = 0, Xor = 0;
27 }
28 /// [l,r]全置为1
29 else if (val_ == 1) {
30 lmax_0 = rmax_0 = max_0 = sum_0 = 0;
31 lmax_1 = rmax_1 = max_1 = sum_1 = len();
32 val = 1, Xor = 0;
33 }
34 /// [l,r]全异或
35 if (Xor_ == 1) {
36 swap(lmax_0,lmax_1); swap(rmax_0,rmax_1);
37 swap(max_0,max_1); swap(sum_0,sum_1);
38 Xor ^= 1;
39 }
40 }
41 }tree[maxn*4];
42 int a[maxn];
43 void pushup(node &fa, node &ls, node &rs) {
44 /// 父节点的左边最长0串=左子树的左边最长0串
45 fa.lmax_0 = ls.lmax_0, fa.rmax_0 = rs.rmax_0;
46 fa.lmax_1 = ls.lmax_1, fa.rmax_1 = rs.rmax_1;
47 /// 父节点0的数量=左子树0的数量+右子树0的数量
48 fa.sum_0 = ls.sum_0+rs.sum_0;
49 fa.sum_1 = ls.sum_1+rs.sum_1;
50 /// 父节点最大连续0串等于左右子树里面中最大连续0串的最大值
51 /// 或者是左子树从右开始的0串+右子树从左开始的0串之和
52 fa.max_0 = max(max(ls.max_0,rs.max_0), ls.rmax_0+rs.lmax_0);
53 fa.max_1 = max(max(ls.max_1,rs.max_1), ls.rmax_1+rs.lmax_1);
54
55 /// 如果左子树整串都为0串
56 if (ls.len() == ls.lmax_0) fa.lmax_0 += rs.lmax_0;
57 if (ls.len() == ls.lmax_1) fa.lmax_1 += rs.lmax_1;
58 if (rs.len() == rs.rmax_0) fa.rmax_0 += ls.rmax_0;
59 if (rs.len() == rs.rmax_1) fa.rmax_1 += ls.rmax_1;
60 }
61 void pushdown(int rt) {
62 if (tree[rt].val != -1 || tree[rt].Xor) {
63 tree[rt*2].change(tree[rt].val,tree[rt].Xor);
64 tree[rt*2+1].change(tree[rt].val,tree[rt].Xor);
65 tree[rt].val = -1, tree[rt].Xor = 0;
66 }
67 }
68 void build(int rt, int l, int r) {
69 /// 结点初始化
70 tree[rt].l = l, tree[rt].r = r;
71 tree[rt].lmax_0 = tree[rt].rmax_0 = 0;
72 tree[rt].lmax_1 = tree[rt].rmax_1 = 0;
73 tree[rt].max_0 = tree[rt].max_1 = 0;
74 tree[rt].sum_0 = tree[rt].sum_1 = 0;
75 tree[rt].Xor = 0, tree[rt].val = -1;
76 /// 如果是叶子结点
77 if (l == r) {
78 tree[rt].change(a[l],0);
79 return;
80 }
81 int mid = (l+r)/2;
82 build(rt*2,l,mid);
83 build(rt*2+1,mid+1,r);
84 pushup(tree[rt],tree[rt*2],tree[rt*2+1]);
85 }
86 void update(int rt, int l, int r, int op) {
87 int L = tree[rt].l, R = tree[rt].r;
88 if (l <= L && R <= r) {
89 /// 根据op执行不同操作
90 if (op == 0 || op == 1) tree[rt].change(op,0);
91 else if (op == 2) tree[rt].change(-1,1);
92 return;
93 }
94 pushdown(rt);
95 int mid = (L+R)/2;
96 if (mid >= l) update(rt*2,l,r,op);
97 if (mid < r) update(rt*2+1,l,r,op);
98 pushup(tree[rt],tree[rt*2],tree[rt*2+1]);
99 }
100 int query(int rt, int l, int r, int op) {
101 int L = tree[rt].l, R = tree[rt].r;
102 if (l <= L && R <= r) {
103 if (op == 3) return tree[rt].sum_1;
104 else if (op == 4) return tree[rt].max_1;
105 }
106 int mid = (L+R)/2;
107 pushdown(rt);
108 if (r <= mid) return query(rt*2,l,r,op);
109 else if (l > mid) return query(rt*2+1,l,r,op);
110 else {
111 int max1 = query(rt*2,l,r,op);
112 int max2 = query(rt*2+1,l,r,op);
113 if (op == 3) return max1+max2;
114 int max3 = min(tree[rt*2].r-l+1,tree[rt*2].rmax_1)+min(r-tree[rt*2+1].l+1,tree[rt*2+1].lmax_1);
115 return max(max(max1,max2),max3);
116 }
117 }
118 int main() {
119 int t; scanf("%d",&t);
120 while (t--) {
121 int n, m; scanf("%d%d",&n,&m);
122 for (int i = 0; i < n; ++i)
123 scanf("%d",&a[i]);
124 build(1,0,n-1);
125 while (m--) {
126 int op, a, b;
127 scanf("%d%d%d",&op,&a,&b);
128 if (op == 0 || op == 1 || op == 2) update(1,a,b,op);
129 else printf("%d\n",query(1,a,b,op));
130 }
131 }
132 return 0;
133 }