二进制
题目背景:
分析:线段树
比较显然的可以看出来,如果对于一个子区间,区间中的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; }