题意:
0, 1序列
两种操作:
1. 将一段区间内的 0 与 1 翻转
2. 询问一段区间内最长的连续的 1 的个数
对于每个区间而言记录如下信息:
左起连续的 1 的个数,右起连续的 1 的个数,整段区间最长的连续的 1 的个数
左起连续的 0 的个数,右起连续的 0 的个数,整段区间最长的连续的 0 的个数
之所以要记录 0 是为了方便翻转后信息的修改
显见,这些信息记录下来后,就不需要具体地知道每个位置究竟是 0 还是 1 了
然后再注意一下合并的细节之类的就行了
但是这道题有个很 tricky 的地方(也许只是我个人这么觉得…)
对于 tag 的修改(在 modify 时以及 push_down 时)并不能直接置 1,要注意到 tag 的叠加性,也许这次的修改是恰好抵消了前一次的修改呢
(致谢点击打开链接,还是在看了原PO写的之后才意识到原来WA在了这里...)
AC代码如下:
#include <cstdio>
#define lson ((rt) << 1)
#define rson ((rt) << 1 | 1)
#define maxn 100010
inline max(int a, int b) { return a > b ? a : b; }
inline min(int a, int b) { return a < b ? a : b; }
inline midi(int a, int b) { return (a + b) >> 1; }
inline swap(int& a, int& b) { int temp = a; a = b; b = temp; }
struct node {
int l1, l0, r1, r0, t1, t0, len, l, r;
bool flag;
}tree[maxn * 4];
int n, m;
void lift_up(int rt) {
tree[rt].l1 = tree[lson].l1; tree[rt].l0 = tree[lson].l0;
if (tree[rt].l1 == tree[lson].len) tree[rt].l1 += tree[rson].l1;
if (tree[rt].l0 == tree[lson].len) tree[rt].l0 += tree[rson].l0;
tree[rt].r1 = tree[rson].r1; tree[rt].r0 = tree[rson].r0;
if (tree[rt].r1 == tree[rson].len) tree[rt].r1 += tree[lson].r1;
if (tree[rt].r0 == tree[rson].len) tree[rt].r0 += tree[lson].r0;
tree[rt].t1 = max(max(tree[lson].t1, tree[rson].t1), tree[lson].r1 + tree[rson].l1);
tree[rt].t0 = max(max(tree[lson].t0, tree[rson].t0), tree[lson].r0 + tree[rson].l0);
}
void build(int rt, int l, int r) {
tree[rt].l = l; tree[rt].r = r; tree[rt].len = r - l + 1; tree[rt].flag = 0;
if (l == r) {
int x;
scanf("%d", &x);
tree[rt].l1 = tree[rt].r1 = tree[rt].t1 = x;
tree[rt].l0 = tree[rt].r0 = tree[rt].t0 = 1 - x;
return;
}
int mid = midi(l, r);
build(lson, l, mid); build(rson, mid + 1, r);
lift_up(rt);
}
void push_down(int rt) {
if (tree[rt].flag) {
swap(tree[lson].l1, tree[lson].l0); swap(tree[lson].r1, tree[lson].r0);
swap(tree[lson].t1, tree[lson].t0);
swap(tree[rson].l1, tree[rson].l0); swap(tree[rson].r1, tree[rson].r0);
swap(tree[rson].t1, tree[rson].t0);
tree[lson].flag ^= 1;
tree[rson].flag ^= 1;
tree[rt].flag = 0;
}
}
int query(int rt, int l, int r) {
if (tree[rt].l == l && tree[rt].r == r) return tree[rt].t1;
push_down(rt);
int mid = midi(tree[rt].l, tree[rt].r);
if (r <= mid) return query(lson, l, r);
else if (l > mid) return query(rson, l, r);
else {
int ans1 = query(lson, l, mid), ans2 = query(rson, mid + 1, r),
ans3 = min(mid - l + 1, tree[lson].r1) + min(r - mid, tree[rson].l1);
return max(max(ans1, ans2), ans3);
}
}
void modify(int rt, int l, int r) {
if (tree[rt].l == l && tree[rt].r == r) {
swap(tree[rt].l1, tree[rt].l0); swap(tree[rt].r1, tree[rt].r0);
swap(tree[rt].t1, tree[rt].t0);
tree[rt].flag ^= 1;
return;
}
push_down(rt);
int mid = midi(tree[rt].l, tree[rt].r);
if (r <= mid) modify(lson, l, r);
else if (l > mid) modify(rson, l, r);
else { modify(lson, l, mid); modify(rson, mid + 1, r); }
lift_up(rt);
}
void work() {
build(1, 1, n);
scanf("%d", &m);
for (int i = 0; i < m; ++i) {
int x, l, r;
scanf("%d%d%d", &x, &l, &r);
if (x == 0) printf("%d\n", query(1, l, r));
else modify(1, l, r);
}
}
int main() {
while (scanf("%d", &n) != EOF) work();
return 0;
}
题意:
0, 1序列
五种操作:
1. 将一段区间全置 0
2. 将一段区间全置 1
3. 将一段区间 0, 1 翻转
4. 询问一段区间内 1 的总数
5. 询问一段区间内最长的连续的 1 的个数
显见对于连续的 1 的个数的处理和上一题(hdu 3911)一模一样
而 1 的总数的记录就是最简单的那样
所以这道题关键的地方就在于 tag 怎么处理
用了两个 tag,来分别表示 第三种操作(flag1) 和 前两种操作(flag2),
在,分别初始化为 flag1 = 0, flag2 = -1
(事实上,对于 flag1 的处理和上一题中一模一样)
显见,前两种操作的优先级是比第三种操作要高的,所以
在 push_down 时,首先根据 flag2 来 push,如果 flag2 == -1,再去根据 flag1 来 push;
在 modify 时,
如果当前操作是前两种操作,那么直接修改flag2;
如果当前操作是第三种操作,如果 flag2 != -1(这意味着记录下的当前段的状态是全 0 或 全 1,第三种操作进行后也是变为 全 1 或 全 0), 那么 flag2 取反;否则修改 flag1
(顺便说一句,这道题写完后根本不想检查
然后
一遍A的感觉真是太爽了库库库)
AC代码如下:
#include <cstdio>
#define lson ((rt) << 1)
#define rson ((rt) << 1 | 1)
#define maxn 100010
inline max(int a, int b) { return a > b ? a : b; }
inline min(int a, int b) { return a < b ? a : b; }
inline midi(int a, int b) { return (a + b) >> 1; }
inline swap(int& a, int& b) { int temp = a; a = b; b = temp; }
int n, m;
struct node {
int l, r, num, l1, l0, r1, r0, t1, t0, len, flag1, flag2;
}tree[maxn * 4];
void lift_up(int rt) {
tree[rt].num = tree[lson].num + tree[rson].num;
tree[rt].l1 = tree[lson].l1; tree[rt].r1 = tree[rson].r1;
if (tree[rt].l1 == tree[lson].len) tree[rt].l1 += tree[rson].l1;
if (tree[rt].r1 == tree[rson].len) tree[rt].r1 += tree[lson].r1;
tree[rt].l0 = tree[lson].l0; tree[rt].r0 = tree[rson].r0;
if (tree[rt].l0 == tree[lson].len) tree[rt].l0 += tree[rson].l0;
if (tree[rt].r0 == tree[rson].len) tree[rt].r0 += tree[lson].r0;
tree[rt].t1 = max(max(tree[lson].t1, tree[rson].t1), tree[lson].r1 + tree[rson].l1);
tree[rt].t0 = max(max(tree[lson].t0, tree[rson].t0), tree[lson].r0 + tree[rson].l0);
}
void push_down(int rt) {
if (tree[rt].flag2 != -1) {
tree[lson].l1 = tree[lson].r1 = tree[lson].t1 = tree[lson].num = tree[rt].flag2 * tree[lson].len;
tree[lson].l0 = tree[lson].r0 = tree[lson].t0 = (1 - tree[rt].flag2) * tree[lson].len;
tree[rson].l1 = tree[rson].r1 = tree[rson].t1 = tree[rson].num = tree[rt].flag2 * tree[rson].len;
tree[rson].l0 = tree[rson].r0 = tree[rson].t0 = (1 - tree[rt].flag2) * tree[rson].len;
tree[lson].flag2 = tree[rson].flag2 = tree[rt].flag2;
tree[rt].flag2 = -1; tree[rt].flag1 = 0;
return;
}
if (tree[rt].flag1) {
swap(tree[lson].l1, tree[lson].l0); swap(tree[lson].r1, tree[lson].r0);
swap(tree[lson].t1, tree[lson].t0); tree[lson].num = tree[lson].len - tree[lson].num;
swap(tree[rson].l1, tree[rson].l0); swap(tree[rson].r1, tree[rson].r0);
swap(tree[rson].t1, tree[rson].t0); tree[rson].num = tree[rson].len - tree[rson].num;
if (tree[lson].flag2 != -1) tree[lson].flag2 = 1 - tree[lson].flag2;
else tree[lson].flag1 ^= 1;
if (tree[rson].flag2 != -1) tree[rson].flag2 = 1 - tree[rson].flag2;
else tree[rson].flag1 ^= 1;
tree[rt].flag2 = -1; tree[rt].flag1 = 0;
}
}
void build(int rt, int l, int r) {
tree[rt].l = l; tree[rt].r = r; tree[rt].len = r - l + 1; tree[rt].flag1 = 0; tree[rt].flag2 = -1;
if (l == r) {
int x;
scanf("%d", &x);
tree[rt].num = tree[rt].l1 = tree[rt].r1 = tree[rt].t1 = x;
tree[rt].l0 = tree[rt].r0 = tree[rt].t0 = 1 - x;
return;
}
int mid = midi(l, r);
build(lson, l, mid); build(rson, mid + 1, r);
lift_up(rt);
}
void modify(int rt, int l, int r, int x) {
// printf("%d\n", rt);
if (tree[rt].l == l && tree[rt].r == r) {
if (x == 0 || x == 1) {
tree[rt].num = tree[rt].l1 = tree[rt].r1 = tree[rt].t1 = x * tree[rt].len;
tree[rt].l0 = tree[rt].r0 = tree[rt].t0 = (1 - x) * tree[rt].len;
tree[rt].flag2 = x; tree[rt].flag1 = 0;
}
else {
tree[rt].num = tree[rt].len - tree[rt].num;
swap(tree[rt].l1, tree[rt].l0); swap(tree[rt].r1, tree[rt].r0);
swap(tree[rt].t1, tree[rt].t0);
if (tree[rt].flag2 != -1) tree[rt].flag2 = 1 - tree[rt].flag2;
else tree[rt].flag1 ^= 1;
}
return;
}
push_down(rt);
int mid = midi(tree[rt].l, tree[rt].r);
if (r <= mid) modify(lson, l, r, x);
else if (l > mid) modify(rson, l, r, x);
else { modify(lson, l, mid, x); modify(rson, mid + 1, r, x); }
lift_up(rt);
}
int query(int rt, int l, int r, int x) {
// printf("%d\n", rt);
if (tree[rt].l == l && tree[rt].r == r) {
if (x == 0) return tree[rt].num;
return tree[rt].t1;
}
push_down(rt);
int mid = midi(tree[rt].l, tree[rt].r);
if (r <= mid) return query(lson, l, r, x);
else if (l > mid) return query(rson, l, r, x);
else {
if (x == 0) return query(lson, l, mid, x) + query(rson, mid + 1, r, x);
else {
int ans1 = query(lson, l, mid, x), ans2 = query(rson, mid + 1, r, x),
ans3 = min(mid - l + 1, tree[lson].r1) + min(r - mid, tree[rson].l1);
return max(max(ans1, ans2), ans3);
}
}
}
void work() {
build(1, 1, n);
for (int i = 0; i < m; ++i) {
int op, l, r;
scanf("%d%d%d", &op, &l, &r); ++l; ++r;
switch (op) {
case 0:
case 1:
case 2: modify(1, l, r, op);
break;
case 3:
case 4: printf("%d\n", query(1, l, r, op - 3)); break;
}
}
}
int main() {
// freopen("3397.in", "r", stdin);
int T;
scanf("%d", &T);
while (scanf("%d%d", &n, &m) != EOF) work();
return 0;
}