分块算法入门及简单习题
分块算法也算是一种暴力算法,可以解决一些区间问题(数据没有卡分块)。写起来比较简单。随着知识的增长,发现线段树和线段数组也能很快的解决一些区间问题,而且比分块要快。但是分块也有他自己的优势:容易书写,简单易懂,并且能处理一些线段树不好处理的一些问题。
我认为的一套简单易懂的模板:
for (int i = 1; i <= n; i ++){
a[i] = read();
block[i] = (i - 1) / sz + 1;
v[block[i]].push_back(a[i]);
}
利用vector对每个块里的元素进行储存。
经常会遇到[l,r]区间加x,[l,r]区间小于x的元素等等。
这就要根据实际情况来写出add函数和query函数。add函数和query函数非常相似,可以先写出add函数在将里面的条件一换即可。
下面是几个分块的经典例题:
LibreOJ 6277 https://vjudge.net/problem/LibreOJ-6277/origin
LibreOJ 6278 https://vjudge.net/problem/LibreOJ-6278/origin
LibreOJ 6279 https://vjudge.net/problem/LibreOJ-6279/origin
LibreOJ 6280 https://vjudge.net/problem/LibreOJ-6280/origin
6277:
分块:
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const int maxn = 1e6;
typedef long long ll;
using namespace std;
const ll mod = 1e9 + 7;
const double pi = acos(-1.0);
const double c = 0.57721566490153286060651209;
const double esp = 1e-8;
const int INF = 0x7fffffff;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int a[maxn], tag[maxn], block[maxn], sz, n;
vector<int> v[maxn];
void reset(int x){
v[x].clear();
for (int i = (x - 1) * sz + 1; i <= min(x * sz, n); i ++)
v[x].push_back(a[i]);
sort(v[x].begin(),v[x].end());
}
void add(int l, int r, int c){
for (int i = l; i <= min(block[l] * sz, r); i ++)
a[i] += c;
//reset(block[l]);
if (block[l] != block[r]){
for (int i = (block[r] - 1) * sz + 1; i <= r; i ++)
a[i] += c;
//reset(block[r]);
}
for (int i = block[l] + 1; i <= block[r] - 1; i ++)
tag[i] += c;
}
int solve(int l, int r, int c){
int ans = 0;
for (int i = l; i <= min(block[l] * sz, r); i ++)
if (a[i] + tag[block[l]]< c)
ans ++;
if (block[l] != block[r])
for (int i = (block[r] - 1) * sz + 1; i <= r; i ++)
if (a[i] + tag[block[r]]< c)
ans ++;
for (int i = block[l] + 1; i <= block[r] - 1; i ++)
ans += lower_bound(v[i].begin(),v[i].end(),c-tag[i]) - v[i].begin();
return ans;
}
int main() {
ios::sync_with_stdio(false);
//freopen("text.txt","r",stdin);
//freopen("out1.txt","w",stdout);
int l, r, opt, c;
n = read();
sz = sqrt(n);
for (int i = 1; i <= n; i ++){
a[i] = read();
block[i] = (i - 1) / sz + 1;
v[block[i]].push_back(a[i]);
}
for (int i = 0; i < n; i ++){
opt = read(), l = read(), r = read(), c = read();
if (!opt)
add(l,r,c);
else
cout << a[r] + tag[block[r]] << endl;
}
return 0;
}
树状数组:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const int maxn = 1e6 + 7;
typedef long long ll;
using namespace std;
const ll mod = 1e9 + 7;
const double pi = 3.14;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
int a[maxn], n;
int sum1[maxn], sum2[maxn];
void add(int i, int k){
int x = i;
while(i <= n){
sum1[i] += k;
sum2[i] += k * (x - 1);
i += lowbit(i);
}
}
int sum(int i){
int res = 0, x = i;
while(i > 0){
res += x * sum1[i] - sum2[i];
i -= lowbit(i);
}
return res;
}
int main(){
ios::sync_with_stdio(false);
//freopen("text.txt","r",stdin);
//freopen("out1.txt","w",stdout);
int opt, l, r, c;
cin >> n;
for (int i = 1; i <= n; i ++){
cin >> a[i];
add(i,a[i]);
add(i+1,-a[i]);
}
for (int i = 0; i < n; i ++){
cin >> opt >> l >> r >> c;
if (opt == 0){
add(l,c);
add(r+1,-c);
}
else{
cout << sum(r) - sum(r-1) << endl;
}
}
return 0;
}
6278:
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const int maxn = 1e6;
typedef long long ll;
using namespace std;
const ll mod = 1e9 + 7;
const double pi = acos(-1.0);
const double c = 0.57721566490153286060651209;
const double esp = 1e-8;
const int INF = 0x7fffffff;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int a[maxn], tag[maxn], block[maxn], sz, n;
vector<int> v[maxn];
void reset(int x){
v[x].clear();
for (int i = (x - 1) * sz + 1; i <= min(x * sz, n); i ++)
v[x].push_back(a[i]);
sort(v[x].begin(),v[x].end());
}
void add(int l, int r, int c){
for (int i = l; i <= min(block[l] * sz, r); i ++)
a[i] += c;
reset(block[l]);
if (block[l] != block[r]){
for (int i = (block[r] - 1) * sz + 1; i <= r; i ++)
a[i] += c;
reset(block[r]);
}
for (int i = block[l] + 1; i <= block[r] - 1; i ++)
tag[i] += c;
}
int solve(int l, int r, int c){
int ans = 0;
for (int i = l; i <= min(block[l] * sz, r); i ++)
if (a[i] + tag[block[l]]< c)
ans ++;
if (block[l] != block[r])
for (int i = (block[r] - 1) * sz + 1; i <= r; i ++)
if (a[i] + tag[block[r]]< c)
ans ++;
for (int i = block[l] + 1; i <= block[r] - 1; i ++)
ans += lower_bound(v[i].begin(),v[i].end(),c-tag[i]) - v[i].begin();
return ans;
}
int main() {
ios::sync_with_stdio(false);
//freopen("text.txt","r",stdin);
//freopen("out1.txt","w",stdout);
int l, r, opt, c;
cin >> n;
sz = sqrt(n);
for (int i = 1; i <= n; i ++){
cin >> a[i];
block[i] = (i - 1) / sz + 1;
v[block[i]].push_back(a[i]);
}
for (int i = 1; i <= block[n]; i ++)
sort(v[i].begin(),v[i].end());
for (int i = 0; i < n; i ++){
cin >> opt >> l >> r >> c;
if (!opt)
add(l,r,c);
else
cout << solve(l,r,c*c) << endl;
}
return 0;
}
6279
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const int maxn = 1e6;
typedef long long ll;
using namespace std;
const ll mod = 1e9 + 7;
const double pi = acos(-1.0);
const double c = 0.57721566490153286060651209;
const double esp = 1e-8;
const int INF = 0x7fffffff;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int a[maxn], tag[maxn], block[maxn], sz, n;
vector<int> v[maxn];
void reset(int x){
v[x].clear();
for (int i = (x - 1) * sz + 1; i <= min(x * sz, n); i ++)
v[x].push_back(a[i]);
sort(v[x].begin(),v[x].end());
}
void add(int l, int r, int c){
for (int i = l; i <= min(block[l] * sz, r); i ++)
a[i] += c;
reset(block[l]);
if (block[l] != block[r]){
for (int i = (block[r] - 1) * sz + 1; i <= r; i ++)
a[i] += c;
reset(block[r]);
}
for (int i = block[l] + 1; i <= block[r] - 1; i ++)
tag[i] += c;
}
int solve(int l, int r, int c){
int ans = -1;
for (int i = l; i <= min(block[l] * sz, r); i ++)
if (a[i] + tag[block[l]]< c)
ans = max(ans,a[i] + tag[block[l]]);
if (block[l] != block[r])
for (int i = (block[r] - 1) * sz + 1; i <= r; i ++)
if (a[i] + tag[block[r]]< c)
ans = max(ans,a[i] + tag[block[r]]);
for (int i = block[l] + 1; i <= block[r] - 1; i ++){
int it = lower_bound(v[i].begin(),v[i].end(),c-tag[i]) - v[i].begin();
if (it == 0)
continue;
ans = max(ans,v[i][it-1]+tag[i]);
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
//freopen("text.txt","r",stdin);
//freopen("out1.txt","w",stdout);
int l, r, opt, c;
n = read();
sz = sqrt(n);
for (int i = 1; i <= n; i ++){
a[i] = read();
block[i] = (i - 1) / sz + 1;
v[block[i]].push_back(a[i]);
}
for (int i = 1; i <= n; i ++)
sort(v[i].begin(),v[i].end());
for (int i = 0; i < n; i ++){
opt = read(), l = read(), r = read(), c = read();
if (!opt)
add(l,r,c);
else
cout << solve(l,r,c) << endl;
}
return 0;
}
6280
分块
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const int maxn = 1e6;
typedef long long ll;
using namespace std;
const ll mod = 1e9 + 7;
const double pi = acos(-1.0);
const double c = 0.57721566490153286060651209;
const double esp = 1e-8;
const int INF = 0x7fffffff;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
ll a[maxn], tag[maxn], block[maxn], sum[maxn];
ll sz, n;
void reset(ll x) {
sum[x] = 0;
for (int i = (x - 1) * sz + 1; i <= min(x * sz, n); i++)
sum[x] += a[i];
}
void add(ll l, ll r, ll c) {
for (int i = l; i <= min(block[l] * sz, ll(r)); i++)
a[i] += c;
reset(block[l]);
if (block[l] != block[r]) {
for (int i = (block[r] - 1) * sz + 1; i <= r; i++)
a[i] += c;
reset(block[r]);
}
for (int i = block[l] + 1; i <= block[r] - 1; i++)
tag[i] += c;
}
ll solve(ll l, ll r, ll c) {
ll ans = 0;
for (int i = l; i <= min(block[l] * sz, ll(r)); i++)
ans += (a[i] + tag[block[i]]);
if (block[l] != block[r])
for (int i = (block[r] - 1) * sz + 1; i <= r; i++)
ans += (a[i] + tag[block[i]]);
for (int i = block[l] + 1; i <= block[r] - 1; i++) {
ans += sum[i] + sz * tag[i];
}
return ans % (c + 1);
}
int main() {
//ios::sync_with_stdio(false);
//freopen("text.txt","r",stdin);
//freopen("out1.txt","w",stdout);
ll l, r, opt, c;
scanf("%lld",&n);
sz = sqrt(n);
for (int i = 1; i <= n; i++) {
scanf("%lld",&a[i]);
block[i] = (i - 1) / sz + 1;
}
for (int i = 1; i <= n; i++)
sum[block[i]] += a[i];
for (int i = 0; i < n; i++) {
scanf("%lld%lld%lld%lld",&opt,&l,&r,&c);
if (!opt)
add(l, r, c);
else
cout << solve(l, r, c) << endl;
}
return 0;
}
树状数组
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
const int maxn = 1e6 + 7;
typedef long long ll;
using namespace std;
const ll mod = 1e9 + 7;
const double pi = 3.14;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
ll a[maxn], n;
ll sum1[maxn], sum2[maxn];
void add(int i, int k){
int x = i;
while(i <= n){
sum1[i] += k;
sum2[i] += k * (x - 1);
i += lowbit(i);
}
}
ll sum(int i){
ll res = 0, x = i;
while(i > 0){
res += x * sum1[i] - sum2[i];
i -= lowbit(i);
}
return res;
}
int main(){
ios::sync_with_stdio(false);
//freopen("text.txt","r",stdin);
//freopen("out1.txt","w",stdout);
int opt, l, r, c;
cin >> n;
for (int i = 1; i <= n; i ++){
cin >> a[i];
add(i,a[i]);
add(i+1,-a[i]);
}
for (int i = 0; i < n; i ++){
cin >> opt >> l >> r >> c;
if (opt == 0){
add(l,c);
add(r+1,-c);
}
else{
cout << (sum(r) - sum(l-1)) % (c + 1) << endl;
}
}
return 0;
}