给你一个长度为n的0、1序列,然后对该序列进行m次操作(1<=n, m<=100000)。操作共有5种:
0 a b 将[a, b]上的所有数变为0;
1 a b 将[a, b]上的所有数变为1;
2 a b 将[a, b]上的0变成1,1变成0;
3 a b 输出[a, b]上1的个数;
4 a b 输出[a, b]上最长的连续的1的数目。
刚开始做的时候就想用两个Lazy标记,一个覆盖标记,一个异或标记。但敲的过程中发现两个标记很难处理,于是就去掉了异或标记。敲好调试好交了两次后1015msAC。但我觉得如果用双标记的话应该会更快,于是又重新敲了个双标记的。结果1140msAC,竟然比单标记的还慢了100+ms。想了想,应该是传递异或标记时花了太多的时间吧~~
把两个代码都贴一下:
单“覆盖”标记
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 111111;
int sum[maxn<<2], llen1[maxn<<2], rlen1[maxn<<2], mlen1[maxn<<2];
int cov[maxn<<2];
void f_cov(int c, int l, int r, int rt)
{
cov[rt] = c;
sum[rt] = llen1[rt] = rlen1[rt] = mlen1[rt] = c ? r - l + 1 : 0;
}
void pushUp(int l, int r, int rt)
{
int m = (l + r) >> 1;
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
llen1[rt] = llen1[rt<<1];
rlen1[rt] = rlen1[rt<<1|1];
if (llen1[rt] == m - l + 1)
llen1[rt] += llen1[rt<<1|1];
if (rlen1[rt] == r - m)
rlen1[rt] += rlen1[rt<<1];
mlen1[rt] = max(rlen1[rt<<1] + llen1[rt<<1|1], max(mlen1[rt<<1], mlen1[rt<<1|1]));
}
void pushDown(int l, int r, int rt)
{
if (cov[rt] != -1)
{
int m = (l + r) >> 1;
f_cov(cov[rt], l, m, rt << 1);
f_cov(cov[rt], m + 1, r, rt << 1 | 1);
cov[rt] = -1;
}
}
void build(int l, int r, int rt)
{
cov[rt] = -1;
if (l == r)
{
scanf("%d", &sum[rt]);
cov[rt] = llen1[rt] = rlen1[rt] = mlen1[rt] = sum[rt];
return ;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushUp(l, r, rt);
}
void update_change(int L, int R, int c, int l, int r, int rt)
{
if (L <= l && R >= r)
{
f_cov(c, l, r, rt);
return ;
}
pushDown(l, r, rt);
int m = (l + r) >> 1;
if (L <= m) update_change(L, R, c, l, m, rt << 1);
if (R > m) update_change(L, R, c, m + 1, r, rt << 1 | 1);
pushUp(l, r, rt);
}
void update_xor(int L, int R, int l, int r, int rt)
{
if (L <= l && R >= r)
{
if (cov[rt] != -1)
{
cov[rt] ^= 1;
sum[rt] = llen1[rt] = rlen1[rt] = mlen1[rt] = cov[rt] ? r - l + 1 : 0;
return ;
}
}
pushDown(l, r, rt);
int m = (l + r) >> 1;
if (L <= m) update_xor(L, R, l, m, rt << 1);
if (R > m) update_xor(L, R, m + 1, r, rt << 1 | 1);
pushUp(l, r, rt);
}
int query_sum(int L, int R, int l, int r, int rt)
{
if (L <= l && R >= r)
return sum[rt];
pushDown(l, r, rt);
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret += query_sum(L, R, l, m, rt << 1);
if (R > m) ret += query_sum(L, R, m + 1, r, rt << 1 | 1);
return ret;
}
int query_len(int L, int R, int l, int r, int rt)
{
if (L == l && R == r)
return mlen1[rt];
pushDown(l, r, rt);
int m = (l + r) >> 1;
if (R <= m) return query_len(L, R, l, m, rt << 1);
else if (L > m) return query_len(L, R, m + 1, r, rt << 1 | 1);
else
{
int a = query_len(L, m, l, m, rt << 1);
int b = query_len(m + 1, R, m + 1, r, rt << 1 | 1);
int c = 0;
c += min(rlen1[rt<<1], m - L + 1);
c += min(llen1[rt<<1|1], R - m);
return max(a, max(b, c));
}
}
int main()
{
int t, n, m;
int op, a, b;
scanf("%d", &t);
while (t--)
{
scanf("%d %d", &n, &m);
build(0, n - 1, 1);
while (m--)
{
scanf("%d %d %d", &op, &a, &b);
if (op == 0 || op == 1)
update_change(a, b, op, 0, n - 1, 1);
else if(op == 2)
update_xor(a, b, 0, n - 1, 1);
else if (op == 3)
printf("%d\n", query_sum(a, b, 0, n - 1, 1));
else printf("%d\n", query_len(a, b, 0, n - 1, 1));
}
}
return 0;
}
“覆盖”和“异或”双标记
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 111111;
int sum[maxn<<2], cov[maxn<<2], XOR[maxn<<2];
int llen1[maxn<<2], rlen1[maxn<<2], mlen1[maxn<<2];
int llen0[maxn<<2], rlen0[maxn<<2], mlen0[maxn<<2];
void f_cov(int c, int l, int r, int rt) // 覆盖操作
{
cov[rt] = c;
XOR[rt] = 0; // 覆盖时,异或标记直接清零
sum[rt] = c ? r - l + 1 : 0;
llen0[rt] = rlen0[rt] = mlen0[rt] = c ? 0 : r - l + 1;
llen1[rt] = rlen1[rt] = mlen1[rt] = c ? r - l + 1 : 0;
}
void f_xor(int l, int r, int rt) // 异或操作
{
if (cov[rt] != -1) cov[rt] ^= 1;
else XOR[rt] ^= 1;
sum[rt] = (r - l + 1) - sum[rt];
swap(llen0[rt], llen1[rt]);
swap(rlen0[rt], rlen1[rt]);
swap(mlen0[rt], mlen1[rt]);
}
void pushUp(int l, int r, int rt)
{
int m = (l + r) >> 1;
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
llen1[rt] = llen1[rt<<1];
rlen1[rt] = rlen1[rt<<1|1];
if (llen1[rt] == m - l + 1)
llen1[rt] += llen1[rt<<1|1];
if (rlen1[rt] == r - m)
rlen1[rt] += rlen1[rt<<1];
mlen1[rt] = max(rlen1[rt<<1] + llen1[rt<<1|1], max(mlen1[rt<<1], mlen1[rt<<1|1]));
llen0[rt] = llen0[rt<<1];
rlen0[rt] = rlen0[rt<<1|1];
if (llen0[rt] == m - l + 1)
llen0[rt] += llen0[rt<<1|1];
if (rlen0[rt] == r - m)
rlen0[rt] += rlen0[rt<<1];
mlen0[rt] = max(rlen0[rt<<1] + llen0[rt<<1|1], max(mlen0[rt<<1], mlen0[rt<<1|1]));
}
void pushDown(int l, int r, int rt)
{
int m = (l + r) >> 1;
if (cov[rt] != -1)
{
f_cov(cov[rt], l, m, rt << 1);
f_cov(cov[rt], m + 1, r, rt << 1 | 1);
cov[rt] = -1;
}
if (XOR[rt])
{
f_xor(l, m, rt << 1);
f_xor(m + 1, r, rt << 1 | 1);
XOR[rt] = 0;
}
}
void build(int l, int r, int rt)
{
cov[rt] = -1;
XOR[rt] = 0;
if (l == r)
{
scanf("%d", &sum[rt]);
cov[rt] = llen1[rt] = rlen1[rt] = mlen1[rt] = sum[rt];
llen0[rt] = rlen0[rt] = mlen0[rt] = 1 - sum[rt];
return ;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushUp(l, r, rt);
}
void update(int L, int R, int c, int l, int r, int rt)
{
if (L <= l && R >= r)
{
if (c == 0 || c == 1)
f_cov(c, l, r, rt);
if (c == 2)
f_xor(l, r, rt);
return ;
}
pushDown(l, r, rt);
int m = (l + r) >> 1;
if (L <= m) update(L, R, c, l, m, rt << 1);
if (R > m) update(L, R, c, m + 1, r, rt << 1 | 1);
pushUp(l, r, rt);
}
int query_sum(int L, int R, int l, int r, int rt)
{
if (L <= l && R >= r)
return sum[rt];
pushDown(l, r, rt);
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret += query_sum(L, R, l, m, rt << 1);
if (R > m) ret += query_sum(L, R, m + 1, r, rt << 1 | 1);
return ret;
}
int query_len(int L, int R, int l, int r, int rt)
{
if (L == l && R == r)
return mlen1[rt];
pushDown(l, r, rt);
int m = (l + r) >> 1;
if (R <= m) return query_len(L, R, l, m, rt << 1);
else if (L > m) return query_len(L, R, m + 1, r, rt << 1 | 1);
else
{
int a = query_len(L, m, l, m, rt << 1);
int b = query_len(m + 1, R, m + 1, r, rt << 1 | 1);
int c = 0;
c += min(rlen1[rt<<1], m - L + 1);
c += min(llen1[rt<<1|1], R - m);
return max(a, max(b, c));
}
}
int main()
{
int t, n, m;
int op, a, b;
scanf("%d", &t);
while (t--)
{
scanf("%d %d", &n, &m);
build(0, n - 1, 1);
while (m--)
{
scanf("%d %d %d", &op, &a, &b);
if (op <= 2)
update(a, b, op, 0, n - 1, 1);
else if (op == 3)
printf("%d\n", query_sum(a, b, 0, n - 1, 1));
else printf("%d\n", query_len(a, b, 0, n - 1, 1));
}
}
return 0;
}