n长的区间上,定义四种操作:
1)F a b [a,b]置为1
2)E a b [a,b]置为0
3)I a b [a,b]取反
4)Q a b 询问sum(a,b)
这种题亦有一种说法叫做染色。。前面两种操作,用一般的区间修改即可完成,对于最关键的取反操作,要根据原来的标记值确定更新后的值。
如,标记:0,1,2分别表示置为0,置为1,取反,-1为未标记
set(x):
if flag(x) == 0 or flag(x) == 1:
set_flag(x, !flag(x))
elif flag(x) == 2:
set_flag(x, -1)
elif flag(x) == -1:
set_flag(x, 2)
x.sum = (length(x) - x.sum)
做此题的时候,发现自己对于 lazy propagation 仍未理解透彻。于是改变了原来从LRJ哪里copy的线段树风格,学习了网上一些优秀的代码。重构了 lazy propagation 的实现方式。
对比新的实现方式和原来的写法,区别在于下面几点:
1)查询操作:原来的方式中,遇到第一个标记了的点就会返回,并且不会在查询中进行 pushdown 操作。
而新方式统一了有标记和无标记的点的查询方式,一边查询,一边 pushdown。
2)更新操作:原来的方式用一个 maintain 函数来统一维护,新方式中将其分拆为用于更新的 set_node (根据父节点和子节点双方的标记值来更新),和用于一般维护的pushup。个人认为后者更易理解。
新实现方式:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <set>
#include <list>
#include <map>
#include <limits>
using namespace std;
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
#define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i))
#define MAXN 1024000
#define MAXM 999999
#define MOD 1000000007
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
typedef long long LL;
typedef vector<int> veci;
typedef vector<pair<int, int> > vect;
typedef pair<int, int> pairi;
const double maxdouble = numeric_limits<double>::max();
const double eps = 1e-10;
const int INF = 0x7FFFFFFF;
const int maxnode = 1 << 21; // 修改以确保足够大
#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)|1)
struct IntervalTree {
int sumv[maxnode + 1];
int setv[maxnode + 1];
int length;
int p, v;
int qL, qR;
int _sum;
void init(int n) {
length = n;
}
//_query的封装
void query(int L, int R) {
qL = L;
qR = R;
_sum = 0;
_query(1, 1, length);
}
void _query(int o, int L, int R) {
if (qL <= L && qR >= R) {
_sum += sumv[o];
} else {
int M = L + (R-L)/2;
int lc = lson(o), rc = rson(o);
pushdown(o, L, R);
if (qL <= M)
_query(lc, L, M);
if (qR > M)
_query(rc, M+1, R);
pushup(o);
}
}
void setto(int L, int R, int v) {
qL = L;
qR = R;
_set(1, 1, length, v);
}
void _set(int o, int L, int R, int v) {
if (qL <= L && qR >= R) {
set_node(o, L, R, v);
} else {
pushdown(o, L, R);
int M = L + (R-L)/2;
int lc = lson(o), rc = rson(o);
if (qL <= M)
_set(lc, L, M, v);
if (qR > M)
_set(rc, M+1, R, v);
pushup(o);
}
}
void pushdown(int o, int L, int R) {
if (setv[o] != -1) {
int lc = lson(o), rc = rson(o), M = L+(R-L)/2;
set_node(lc, L, M, setv[o]);
set_node(rc, M+1, R, setv[o]);
setv[o] = -1;
}
}
void pushup(int o) {
int lc = lson(o), rc = rson(o);
sumv[o] = sumv[lc] + sumv[rc];
}
void set_node(int o, int L, int R, int v) {
if (v == 0) {
setv[o] = 0;
sumv[o] = 0;
} else if (v == 1) {
setv[o] = 1;
sumv[o] = R - L + 1;
} else {
if (setv[o] == 1 || setv[o] == 0) {
setv[o] = 1^setv[o];
} else if (setv[o] == 2) {
setv[o] = -1;
} else {
setv[o] = 2;
}
sumv[o] = (R - L + 1) - sumv[o];
}
}
void build(char * arr, int o, int L, int R) {
if (L == R) {
sumv[o] = arr[L-1] - '0';
setv[o] = -1;
} else {
int M = L + (R-L)/2;
int lc = 2*o, rc = 2*o+1;
build(arr, lc, L, M);
build(arr, rc, M+1, R);
sumv[o] = sumv[lc] + sumv[rc];
setv[o] = -1;
}
}
};
IntervalTree tree;
char buf[100];
char arr[MAXN+5];
void print() {
printf("# ");
int len = tree.length;
REP(j, 1, len) {
tree.query(j, j);
printf("%d ", tree._sum);
}
printf("#");
printf("\n");
}
int main() {
freopen("input.in", "r", stdin);
int T, m, t, Q;
scanf("%d",&T);
REP(kase, 1, T) {
printf("Case %d:\n",kase);
scanf("%d",&m);
arr[0] = '\0';
char * p = arr;
REP(i, 1, m) {
scanf("%d%s",&t, buf);
int _l = strlen(buf);
REP(j, 1, t) {
strncpy(p, buf, _l);
p += _l;
}
}
*p = NULL;
int len = strlen(arr);
tree.init(len);
tree.build(arr, 1, 1, len);
scanf("%d",&Q);
int l, r;
int q_cnt = 0;
//print();
REP(i, 1, Q) {
scanf("%s%d%d", buf, &l, &r);
++l;++r;
if (buf[0] == 'F') {
tree.setto(l, r, 1);
//print();
} else if (buf[0] == 'E') {
tree.setto(l, r, 0);
//print();
} else if (buf[0] == 'I') {
tree.setto(l, r, 2);
//print();
} else {
tree.query(l, r);
printf("Q%d: %d\n", ++q_cnt, tree._sum);
}
}
//printf("%s\n",arr);
}
return 0;
}
Time: 1886ms 2032ms