二进制
题目背景:
分析:线段树
比较显然的可以看出来,如果对于一个子区间,区间中的1的个数为偶数,显然是可行的,那么考虑奇数个1的情况,显然,如果只有1个1,那么无论如何都是不行的,而如果是3个及以上,那么我们只管三个就可以了,其他的可以像偶数一样处理,我们可以发现,2的整次幂模3的余数是1, 2, 1, 2,偶数个就是采取一个奇次幂 + 一个偶次幂,而多出来的三个,只能选择三个奇次幂或三个偶次幂,这样就是最优的了,所以说,对于由大于等于3的奇数个1的区间,要包含至少两个0才可以满足条件,那么我们相当于要维护在一个区间里,满足某些条件的子区间个数,这个是经典的线段树维护问题,我们考虑记录三个数组,sum[4][3], lx[4][3], rx[4][3],分别表示区间中的总的方案数,包含左端点的方案数,包含右端点的方案数,而对于后面的二维数组,第一位表示包含1的个数,0/1/2/3分别表示0个1/1个1/2个及两个以上的偶数个1/3个及三个以上的奇数个1,第二位表示0的个数,0/1/2分别表示0个0/1个0/2个及两个以上个0。比如说sum[2][1]就是表示,当前区间中,包含有有大于等于2的偶数个1,并且有且仅有一个0的子区间的个数。rx[1][2]表示,当前区间中,包含右端点的子区间中,包含有1个1,至少两个0的子区间个数。在update的过程中合并一下就可以了,只不过常数非常大,具体细节详见代码,所以2.0s非常必要,复杂度O(nlogn)。
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
inline char read() {
static const int IN_LEN = 1024 * 1024;
static char buf[IN_LEN], *s, *t;
if (s == t) {
t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
if (s == t) return -1;
}
return *s++;
}
///*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return ;
if (c == '-') iosig = true;
}
for (x = 0; isdigit(c); c = read())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
*oh++ = c;
}
template<class T>
inline void W(T x) {
static int buf[30], cnt;
if (x == 0) write_char('0');
else {
if (x < 0) write_char('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) write_char(buf[cnt--]);
}
}
inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
/*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
if (c == '-') iosig = true;
for (x = 0; isdigit(c); c = getchar())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int MAXN = 100000 + 10;
int n, m, x, l, r, type;
int a[MAXN];
inline int get1(int x) {
return (x <= 1) ? x : (x % 2 + 2);
}
inline int get0(int x) {
return (x <= 1) ? x : 2;
}
struct node {
long long cnt[2];
long long sum[4][3], lx[4][3], rx[4][3];
/*
00: 0个1, 没有0 /
01: 0个1, 一个0 /
02: 0个1, 大于等于两个0 /
10: 1个1, 没有0
11: 1个1, 一个0
12: 1个1, 大于等于两个0
20: 大于等于2的偶数个1, 没有0 /
21: 大于等于2的偶数个1, 1个0 /
22: 大于等于2的偶数个1, 大于等于两个0 /
30: 大于等于3的奇数个1, 没有0
31: 大于等于3的奇数个1, 1个0
32: 大于等于3的奇数个1, 大于等于两个0 /
*/
inline node operator + (const node &a) const {
node ans, lc = *this, rc = a;
ans.cnt[0] = lc.cnt[0] + rc.cnt[0];
ans.cnt[1] = lc.cnt[1] + rc.cnt[1];
for (int i = 0; i <= 3; ++i)
for (int j = 0; j <= 2; ++j) {
ans.sum[i][j] = lc.sum[i][j] + rc.sum[i][j];
ans.lx[i][j] = lc.lx[i][j];
ans.rx[i][j] = rc.rx[i][j];
}
for (int i1 = 0; i1 <= 3; ++i1)
for (int i0 = 0; i0 <= 2; ++i0)
if (lc.rx[i1][i0]) {
long long x = lc.rx[i1][i0];
for (int j1 = 0; j1 <= 3; ++j1)
for (int j0 = 0; j0 <= 2; ++j0)
if (rc.lx[j1][j0]) {
long long y = rc.lx[j1][j0];
ans.sum[get1(i1 + j1)][get0(i0 + j0)] += x * y;
}
}
int lc0 = lc.cnt[0], lc1 = lc.cnt[1];
int rc0 = rc.cnt[0], rc1 = rc.cnt[1];
for (int i = 0; i <= 3; ++i)
for (int j = 0; j <= 2; ++j) {
ans.lx[get1(lc1 + i)][get0(lc0 + j)] += rc.lx[i][j];
ans.rx[get1(rc1 + i)][get0(rc0 + j)] += lc.rx[i][j];
}
return ans;
}
} tree[MAXN << 2 | 1];
inline void update(int k) {
tree[k] = tree[k << 1] + tree[k << 1 | 1];
}
inline void build(int k, int l, int r) {
if (l == r) {
int x = (a[l] == 1), y = (a[l] == 0);
tree[k].cnt[0] = y, tree[k].cnt[1] = x;
tree[k].sum[x][y] = tree[k].lx[x][y] = tree[k].rx[x][y] = 1;
return ;
}
int mid = l + r >> 1;
build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r), update(k);
}
inline void modify(int k, int l, int r, int pos) {
if (l == r) {
int x = tree[k].cnt[1], y = tree[k].cnt[0];
tree[k].sum[x][y] = tree[k].lx[x][y] = tree[k].rx[x][y] = 0;
std::swap(tree[k].cnt[0], tree[k].cnt[1]);
tree[k].sum[y][x] = tree[k].lx[y][x] = tree[k].rx[y][x] = 1;
return ;
}
int mid = l + r >> 1;
if (pos <= mid) modify(k << 1, l, mid, pos);
else modify(k << 1 | 1, mid + 1, r, pos);
update(k);
}
inline node query(int k, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return tree[k];
int mid = l + r >> 1;
if (qr <= mid) return query(k << 1, l, mid, ql, qr);
else if (ql > mid) return query(k << 1 | 1, mid + 1, r, ql, qr);
else return query(k << 1, l, mid, ql, qr)
+ query(k << 1 | 1, mid + 1, r, ql, qr);
}
inline void solve() {
R(n);
for (int i = 1; i <= n; ++i) R(a[i]);
R(m), build(1, 1, n);
node ans;
long long ret;
while (m--) {
R(type);
if (type == 1) R(x), modify(1, 1, n, x);
else {
R(l), R(r), ans = query(1, 1, n, l, r), ret = 0;
ret = ans.sum[0][0] + ans.sum[0][1] + ans.sum[0][2]
+ ans.sum[2][0] + ans.sum[2][1] + ans.sum[2][2]
+ ans.sum[3][2];
W(ret), write_char('\n');
}
}
}
int main() {
// freopen("binary.in", "r", stdin);
// freopen("binary.out", "w", stdout);
solve();
flush();
return 0;
}