數列分塊入門1--LOJ(和cf同賬號)

數列分塊入門 1

題目鏈接https://loj.ac/problem/6277

 

內存限制:256 MiB時間限制:100 ms

題目描述

給出一個長爲 n 的數列,以及  n個操作,操作涉及區間加法,單點查值。

輸入格式

第一行輸入一個數字 。

第二行輸入 n 個數字,第 i 個數字爲 ai,以空格隔開。

接下來輸入n  行詢問,每行輸入四個數字 opt,l,r,c以空格隔開。

若pot =0  ,表示將位於[l,r]  的之間的數字都加 。

若opt =1 ,表示詢問 ar 的值(l 和 c 忽略)。

輸出格式

對於每次詢問,輸出一行一個數字表示答案。

樣例

樣例輸入

4
1 2 2 3
0 1 3 1
1 0 1 0
0 1 2 2
1 0 2 0

樣例輸出

2
5

數據範圍與提示

對於 100% 的數據1<=n<=50000,-2^31<=others,ans<=2^31 -1.


。。。很顯然這一題我們可以用樹狀數組或者線段樹來做,但既然要練習分塊。。。

分塊實際上就是暴力枚舉,只不過他是優化了的暴力。我們先將1----n分爲sqrt(n)個大小爲sqrt(n)的塊,當然,對於不能完全平方的,我們需要將塊數+1。還需要做的就是將每個塊的左右端點記錄一下:

int t=sqrt(n);
for (int i=1; i<=t; i++){
    L[i]=(i-1)*t+1;
    R[i]=i*t;
}
if (R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;

然後我們將1---n的所有數打上標記(即所屬的塊是哪一個)。接下來進行區間操作的時候我們可以利用線段樹lazy標記的思想,將l和r所屬的塊單獨更新一下,id(l)+1到id(r)-1的塊我們記錄一下這個塊更新了就好了:

int p=id[l],q=id[r];
for (int i=p+1; i<=q-1; i++) add[i]+=c;
for (int i=l ; i<=R[p]; i++) a[i]+=c;
for (int i=L[q]; i<=r; i++) a[i]+=c;

那麼最後的答案就是a[r]+add[id[r]],即它本身的值加上他所屬的塊所加上的值

以下是AC代碼:

#include <bits/stdc++.h>
using namespace std;

const int mac=5e4+10;

inline void in(int &read)
{
    int x=0;
    char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    read=x;
}

inline void out(int x)
{
    if (x>=10){
        out(x/10);
    }
    putchar(x%10+'0');
}

int a[mac],L[mac],R[mac],id[mac],add[mac];

void update(int l,int r,int c)
{
    int p=id[l],q=id[r];
    if (p==q)
        for (int i=l; i<=r; i++) a[i]+=c;
    else {
        for (int i=p+1; i<=q-1; i++) add[i]+=c;
        for (int i=l ; i<=R[p]; i++) a[i]+=c;
        for (int i=L[q]; i<=r; i++) a[i]+=c;
    }
}

int main()
{
    int n;
    in(n);
    for (int i=1; i<=n; i++)
        in(a[i]);
    int t=sqrt(n);
    for (int i=1; i<=t; i++){
        L[i]=(i-1)*t+1;
        R[i]=i*t;
    }
    if (R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;
    for (int i=1; i<=t; i++)
        for (int j=L[i]; j<=R[i]; j++)
            id[j]=i;
    for (int i=1; i<=n; i++){
        int opt,l,r,c;
        in(opt); in(l); in(r); in(c);
        if (!opt) {
            update(l,r,c);
        }
        else {
            out(a[r]+add[id[r]]);
            putchar('\n');
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章