题解:P12846 [蓝桥杯 2025 国 A] 翻转硬币
分析
看到区间反转问题,一般都是想到线段树加上懒修改功能。
但是这里要我们间隔修改,和隔两个修改。
对于间隔修改,把下标
对于隔两个修改,我们可以把下标
但信息不好同步,这里直接取最小公倍数就好了,放到
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m;
vector<int> f;
int Ls[6];
vector<vector<int>> a;
vector<vector<int>> t;
vector<vector<bool>> lz;
void bld(int c, int p, int l, int r) {
if (l == r) {
t[c][p] = a[c][l];
return;
}
int mid = (l + r) >> 1;
bld(c, p<<1, l, mid);
bld(c, p<<1|1, mid+1, r);
t[c][p] = t[c][p<<1] + t[c][p<<1|1];
}
void apply(int c, int p, int l, int r) {
t[c][p] = (r - l + 1) - t[c][p];
lz[c][p] = !lz[c][p];
}
void push(int c, int p, int l, int r) {
if (!lz[c][p]) return;
int mid = (l + r) >> 1;
apply(c, p<<1, l, mid);
apply(c, p<<1|1, mid+1, r);
lz[c][p] = false;
}
void upd(int c, int p, int l, int r, int Lq, int Rq) {
if (Lq > r || Rq < l) return;
if (Lq <= l && r <= Rq) {
apply(c, p, l, r);
return;
}
push(c, p, l, r);
int mid = (l + r) >> 1;
upd(c, p<<1, l, mid, Lq, Rq);
upd(c, p<<1|1, mid+1, r, Lq, Rq);
t[c][p] = t[c][p<<1] + t[c][p<<1|1];
}
int qry(int c, int p, int l, int r, int Lq, int Rq) {
if (Lq > r || Rq < l) return 0;
if (Lq <= l && r <= Rq) {
return t[c][p];
}
push(c, p, l, r);
int mid = (l + r) >> 1;
return qry(c, p<<1, l, mid, Lq, Rq) + qry(c, p<<1|1, mid+1, r, Lq, Rq);
}
void solve() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
f.resize(n+1);
for (int i = 1; i <= n; i++) {
cin >> f[i];
}
for (int r = 0; r < 6; r++) {
if (r == 0) {
Ls[r] = n / 6;
} else {
if (n >= r) Ls[r] = (n - r) / 6 + 1;
else Ls[r] = 0;
}
}
a.assign(6, vector<int>());
for (int r = 0; r < 6; r++) {
if (Ls[r] > 0) a[r].assign(Ls[r], 0);
}
for (int i = 1; i <= n; i++) {
int mod = i % 6;
int idx;
if (mod == 0) idx = i/6 - 1;
else idx = (i - mod) / 6;
a[mod][idx] = f[i];
}
t.assign(6, vector<int>());
lz.assign(6, vector<bool>());
for (int r = 0; r < 6; r++) {
if (Ls[r] > 0) {
t[r].assign(4 * Ls[r] + 5, 0);
lz[r].assign(4 * Ls[r] + 5, false);
bld(r, 1, 0, Ls[r] - 1);
}
}
for (int qi = 0; qi < m; qi++) {
int typ, x, y;
cin >> typ >> x >> y;
if (typ == 1) {
int modx = x % 2;
for (int r = 0; r < 6; r++) {
if (r % 2 != modx) continue;
int d = (r - x%6 + 6) % 6;
int i0 = x + d;
if (i0 > y) continue;
int cnt = (y - i0) / 6;
int i1 = i0 + cnt * 6;
int j0, j1;
if (r == 0) {
j0 = i0/6 - 1;
j1 = i1/6 - 1;
} else {
j0 = (i0 - r)/6;
j1 = (i1 - r)/6;
}
if (j0 <= j1) upd(r, 1, 0, Ls[r]-1, j0, j1);
}
} else if (typ == 2) {
int modx = x % 3;
for (int r = 0; r < 6; r++) {
if (r % 3 != modx) continue;
int d = (r - x%6 + 6) % 6;
int i0 = x + d;
if (i0 > y) continue;
int cnt = (y - i0) / 6;
int i1 = i0 + cnt * 6;
int j0, j1;
if (r == 0) {
j0 = i0/6 - 1;
j1 = i1/6 - 1;
} else {
j0 = (i0 - r)/6;
j1 = (i1 - r)/6;
}
if (j0 <= j1) upd(r, 1, 0, Ls[r]-1, j0, j1);
}
} else if (typ == 3) {
for (int r = 0; r < 6; r++) {
if (Ls[r] == 0) continue;
int d = (r - x%6 + 6) % 6;
int i0 = x + d;
if (i0 > y) continue;
int cnt = (y - i0) / 6;
int i1 = i0 + cnt * 6;
int j0, j1;
if (r == 0) {
j0 = i0/6 - 1;
j1 = i1/6 - 1;
} else {
j0 = (i0 - r)/6;
j1 = (i1 - r)/6;
}
if (j0 <= j1) upd(r, 1, 0, Ls[r]-1, j0, j1);
}
} else if (typ == 4) {
int ans = 0;
for (int r = 0; r < 6; r++) {
if (Ls[r] == 0) continue;
int d = (r - x%6 + 6) % 6;
int i0 = x + d;
if (i0 > y) continue;
int cnt = (y - i0) / 6;
int i1 = i0 + cnt * 6;
int j0, j1;
if (r == 0) {
j0 = i0/6 - 1;
j1 = i1/6 - 1;
} else {
j0 = (i0 - r)/6;
j1 = (i1 - r)/6;
}
if (j0 <= j1) ans += qry(r, 1, 0, Ls[r]-1, j0, j1);
}
cout << ans << "\n";
}
}
return ;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}