洛谷 – P3870 – [TJOI2009]开关
https://www.luogu.org/problem/P3870
这次写的就很漂亮了啊。
注意一下,num是所在块的编号,便于维护整块信息(小心多定义冲突)。
L数组和R数组是保存了单个位置的左右端点,不是每块的左右端点。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10, mod = 1e9 + 7;
int a[maxn], fan[maxn], tag[maxn], L[maxn], R[maxn], sqn;
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
int n, q;
cin >> n >> q;
sqn = sqrt(n);
//记录每个点所在块的左右端点
int tl = 1, tr = 1 + sqn - 1;
for (int i = 1; i <= n; ++i){
L[i] = tl, R[i] = min(tr, n);
if (i % sqn == 0) tl += sqn, tr += sqn;
}
int p, l, r;
while (q--){
cin >> p >> l >> r;
if (p == 0){
for (int i = l; i <= r; ++i){
int num = (i + sqn - 1) / sqn;
if (i == L[i] && i + sqn - 1 <= r){
fan[num] ^= 1;
tag[num] = R[i] - L[i] + 1 - tag[num];
i += sqn - 1;
}else{
a[i] ^= 1;
if ((a[i] ^ fan[num]) == 1) ++tag[num];
else --tag[num];
}
}
}else{
int ans = 0;
for (int i = l; i <= r; ++i){
int num = (i + sqn - 1) / sqn;
if (i == L[i] && i + sqn - 1 <= r){
ans += tag[num];
i += sqn - 1;
}else{
if ((a[i] ^ fan[num]) == 1) ++ans;
}
}
cout << ans << '\n';
}
}
return 0;
}
洛谷 – P2801 – 教主的魔法
https://www.luogu.org/problem/P2801
数据水警告!这题数据特别水。
这是我第一次写的分块写的特别丑,之后写上面这题的时候优化了很多语句和结构,应该就是最终的模板了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10, mod = 1e9 + 7;
int a[maxn], kuai[maxn], tag[1010], L[1010], R[1010], sqn;
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
int n, q;
cin >> n >> q;
sqn = sqrt(n);
for (int i = 1; i <= n; ++i){
cin >> a[i];
kuai[i] = a[i];
}
int num = 1;
for (int i = 1; 1; i += sqn){
if (i + sqn > n){
L[num] = i, R[num] = n + 1;
sort(kuai + i, kuai + 1 + n);
break;
}
L[num] = i, R[num] = i + sqn;
sort(kuai + i, kuai + i + sqn);
++num;
}
char p;
int l, r, c;
while (q--){
cin >> p >> l >> r >> c;
int numl = (l + sqn - 1) / sqn, numr = (r + sqn - 1) / sqn;
if (p == 'M'){
if (l > L[numl]){
while (l < R[numl]) a[l++] += c;
for (int i = L[numl]; i < R[numl]; ++i) kuai[i] = a[i];
sort(kuai + L[numl], kuai + R[numl]);
++numl;
}
if (r < R[numr] - 1){
while (r >= L[numr]) a[r--] += c;
for (int i = L[numr]; i < R[numr]; ++i) kuai[i] = a[i];
sort(kuai + L[numr], kuai + R[numr]);
--numr;
}
while (numl <= numr){
tag[numl++] += c;
}
}else{
int ans = 0;
if (l > L[numl]){
while (l < R[numl]){
if (a[l++] + tag[numl] >= c) ++ans;
}
++numl;
}
if (r < R[numr] - 1){
while (r >= L[numr]){
if (a[r--] + tag[numr] >= c) ++ans;
}
--numr;
}
while (numl <= numr){
ans += (R[numl] - L[numl]) - (lower_bound(kuai + L[numl], kuai + R[numl], c - tag[numl]) - (kuai + L[numl]));
++numl;
}
cout << ans << '\n';
}
}
return 0;
}
等于(==、!=)的优先级比位运算(&、^、|)要高!
一起写的时候记得加括号!