分块算法入门及简单习题

分块算法入门及简单习题
分块算法也算是一种暴力算法,可以解决一些区间问题(数据没有卡分块)。写起来比较简单。随着知识的增长,发现线段树和线段数组也能很快的解决一些区间问题,而且比分块要快。但是分块也有他自己的优势:容易书写,简单易懂,并且能处理一些线段树不好处理的一些问题。
我认为的一套简单易懂的模板:

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;
}

你可能感兴趣的:(分块算法入门及简单习题)