博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Bzoj5294/洛谷P4428 [Bjoi2018]二进制(线段树)
阅读量:5131 次
发布时间:2019-06-13

本文共 4105 字,大约阅读时间需要 13 分钟。

题面

题解

考虑一个什么样的区间满足重组之后可以变成\(3\)的倍数。不妨设\(tot\)为一个区间内\(1\)的个数。如果\(tot\)是个偶数,则这个区间一定是\(3\)的倍数,接着考虑奇数的情况。

如果只有\(1\)\(1\),那么无论如何都不行,只需考虑\(3\)\(1\)的情况,因为其他的\(1\)可以看做偶数个\(1\)的情况。不难发现,当只有\(3\)\(1\)的时候,我们需要有至少\(2\)\(0\),接着就可以用线段树来维护了。

我们考虑记录三个数组,\(sum[4][3], lx[4][3], rx[4][3]\),分别表示区间中的总的方案数,包含左端点的方案数,包含右端点的方案数。

而对于后面的二维数组,第一位表示包含\(1\)的个数,分别表示有零个\(1\),一个\(1\),有偶数(大于\(0\))个\(1\),有奇数(大于\(1\))个一

二位表示\(0\)的个数,分别表示有零个\(0\),一个\(0\),以及两个及以上个\(0\)

比如说\(sum[2][1]\)就是表示,当前区间中,包含有偶数个\(1\),并且有且仅有一个\(0\)的子区间的个数。

接着的难点就是写\(pushup\)了,可以参考代码。

#include 
#include
#include
using std::min; using std::max;using std::sort; using std::swap;typedef long long ll;template
void read(T &x) { int flag = 1; x = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); } while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;}const int N = 1e5 + 10;int n, m, x, l, r, opt, a[N];inline int get1(int x) { return (x <= 1) ? x : (x % 2 + 2); }inline int get0(int x) { return (x <= 1) ? x : 2; }struct Matrix { ll cnt[2], sum[4][3], lx[4][3], rx[4][3]; Matrix operator + (const Matrix & a) const { Matrix ret, lc = *this, rc = a; ret.cnt[0] = lc.cnt[0] + rc.cnt[0]; ret.cnt[1] = lc.cnt[1] + rc.cnt[1]; for(int i = 0; i < 4; ++i) for(int j = 0; j < 3; ++j) { ret.sum[i][j] = lc.sum[i][j] + rc.sum[i][j]; ret.lx[i][j] = lc.lx[i][j], ret.rx[i][j] = rc.rx[i][j]; } for(int i1 = 0; i1 < 4; ++i1) for(int i0 = 0; i0 < 3; ++i0) if(lc.rx[i1][i0]) { ll x = lc.rx[i1][i0]; for(int j1 = 0; j1 < 4; ++j1) for(int j0 = 0; j0 < 3; ++j0) if(rc.lx[j1][j0]) { ll y = rc.lx[j1][j0]; ret.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 < 4; ++i) for(int j = 0; j < 3; ++j) { ret.lx[get1(lc1 + i)][get0(lc0 + j)] += rc.lx[i][j]; ret.rx[get1(rc1 + i)][get0(rc0 + j)] += lc.rx[i][j]; } return ret; }} t[N << 2];inline void pushup(int o, int lc, int rc) { t[o] = t[lc] + t[rc]; }void build(int o = 1, int l = 1, int r = n) { if(l == r) { int x = (a[l] == 1), y = (a[l] == 0); t[o].cnt[0] = y, t[o].cnt[1] = x; t[o].sum[x][y] = t[o].lx[x][y] = t[o].rx[x][y] = 1; return ; } int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1; build(lc, l, mid), build(rc, mid + 1, r), pushup(o, lc, rc);}void modify(int k, int o = 1, int l = 1, int r = n) { if(l == r) { int x = t[o].cnt[1], y = t[o].cnt[0]; t[o].sum[x][y] = t[o].lx[x][y] = t[o].rx[x][y] = 0; swap(t[o].cnt[0], t[o].cnt[1]); t[o].sum[y][x] = t[o].lx[y][x] = t[o].rx[y][x] = 1; return ; } int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1; if(k <= mid) modify(k, lc, l, mid); else modify(k, rc, mid + 1, r); pushup(o, lc, rc);}Matrix query(int ql, int qr, int o = 1, int l = 1, int r = n) { if(l >= ql && r <= qr) return t[o]; int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1; if(qr <= mid) return query(ql, qr, lc, l, mid); else if(ql > mid) return query(ql, qr, rc, mid + 1, r); else return query(ql, qr, lc, l, mid) + query(ql, qr, rc, mid + 1, r);}int main () { read(n); for(int i = 1; i <= n; ++i) read(a[i]); read(m), build(); Matrix ans; ll ret; while(m--) { read(opt); if(opt == 1) read(x), modify(x); else { read(l), read(r), ans = query(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]; printf("%lld\n", ret); } } return 0;}

转载于:https://www.cnblogs.com/water-mi/p/10350483.html

你可能感兴趣的文章
Android-多线程AsyncTask
查看>>
LeetCode【709. 转换成小写字母】
查看>>
CF992E Nastya and King-Shamans(线段树二分+思维)
查看>>
如果没有按照正常的先装iis后装.net的顺序,可以使用此命令重新注册一下:
查看>>
linux install ftp server
查看>>
alter database databasename set single_user with rollback IMMEDIATE 不成功问题
查看>>
【题解】青蛙的约会
查看>>
autopep8
查看>>
GIT在Linux上的安装和使用简介
查看>>
Android 官方新手指导教程
查看>>
幸运转盘v1.0 【附视频】我的Android原创处女作,请支持!
查看>>
[51nod] 1199 Money out of Thin Air #线段树+DFS序
查看>>
Red and Black(poj-1979)
查看>>
安装 Express
查看>>
存储(硬件方面的一些基本术语)
查看>>
观察者模式
查看>>
Weka中数据挖掘与机器学习系列之基本概念(三)
查看>>
Win磁盘MBR转换为GUID
查看>>
大家在做.NET B/S项目的时候多用什么设技术啊?
查看>>
Java SE和Java EE应用的性能调优
查看>>