problem description剛剛看到本題,很顯然,我們可以先嘗試一下暴力,當然,如果分塊的話,我們也可以大大加快我們對本題的處理。已知乙個數列,你需要進行下面兩種操作:
1.將某區間每乙個數加上x
2.求出某區間每乙個數的和
input
第一行包含兩個整數n、m,分別表示該數列數字的個數和操作的總個數。
第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。
接下來m行每行包含3或4個整數,表示乙個操作,具體如下:
操作1: 格式:1 x y k 含義:將區間[x,y]內每個數加上k
操作2: 格式:2 x y 含義:輸出區間[x,y]內每個數的和
output
包含若干行整數,即為所有操作2的結果。
sample input
5 51 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
sample output118
20tip
時空限制:1000ms,128m
data constraint
對於30%的資料:n≤8,m≤10
對於70%的資料:n≤1000,m≤10000
對於100%的資料:n≤100000,m≤100000
那麼我們就有非常簡單的暴力**。
#include #define ll long long
using namespace std;
ll n,m;
ll a[1000001];
int main()
break;
} }}
觀察本題,很顯然我們需要建立一棵線段樹,其每個節點都儲存一段區間的和, 並且我們可能需要乙個布林函式來幫助我們快速修改一段區間的值。當然,如果題目只是乙個值乙個值修改的話,我們可以選擇樹狀陣列來更快地處理問題。
那麼,什麼是線段樹呢?
線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。簡單來說,線段樹的建立,一般是將乙個陣列tree,每乙個編號i都算乙個節點,那麼我們就可以得到任意乙個線段樹的節點 tree[i],並且使用結構體的方式儲存。
這樣,我們的tree[i],就可以記錄下它儲存的區間和的左端點 left 和右端點 right,以及這段區間的和 sum。同時,線段樹之所以是線段樹,是因為它的祖先、兒子存在包含關係。
簡單來說,如果我已經有乙個節點tree[i],那麼我們通過它所儲存的區間的中點 mid=(left+right)/2 ,那麼我可以再為這個節點 tree[i] 記錄兩個值 leftson , rightson ,表示它的左兒子和右兒子,那麼,左右兒子分別繼承父親節點的一部分區間和,為了盡量降低複雜度,我們選擇左右兒子分別繼承父親節點的一半區間,所得到的左兒子 tree[leftson] ,它的區間左端點仍為 left , 右端點變成了mid 。所以右兒子 tree[rightson],它的區間左端點則為 mid+1 ,右端點則是 right 。由此我們明白,左右兒子所記錄的區間和就是父親節點記錄的區間和,那麼我們就可以通過這一點,進行乙個搜尋。
我們從根節點進行搜尋一段區間,判斷這段區間是繼承到了左兒子還是右兒子處,也可能是兩個兒子分別占有一部分,然後分別進行搜尋,就可以得到答案。
也正是因為每個節點記錄的是一段區間和,所以我們修改一段區間的數的大小時,我們只需乙個節點乙個節點處理就可以了,當然,為了節約時間,我們可以引入變數 change 來記錄這個節點的所有兒子和它是否需要修改,然後在我們遍歷到存在change 的點時,我們只需要增加該節點的和,並將change繼承給它的各個兒子,就可以了。
所以,我們有如下**。
#include #define ll long long
using namespace std;
ll n,m;
ll q[100010];
struct nodev[270000];
void build(ll ,ll ,ll );
void change(ll ,ll ,ll ,ll );
ll find(ll ,ll ,ll );
int main()
else
printf("%lld\n",find(1,x,y));
}return 0;}
ll find(ll ro,ll le,ll ri)
void change(ll ro,ll le,ll ri,ll ca)
if (le>mid)
change(ro<<1,le,mid,ca);
change(ro<<1|1,mid+1,ri,ca);
return ;}
void build(ll ro,ll le,ll ri)
else
v[ro].sum=q[le];
return ;
}
線段樹(模板題)
對於一條數鏈,二分,然後二分,然後再二分 給定一數列,規定有兩種操作,一是修改某個元素,二是求區間的連續和。數列元素初始化為0 輸入 輸入資料第一行包含兩個正整數n,m n 100000,m 500000 以下是m行,每行有三個正整數k,a,b k 0或1,a,b n k 0時表示將a處數字加上b,...
線段樹之模板題
關於線段樹 首先應該是建樹 c國的死對頭a國這段時間正在進行軍事演習,所以c國間諜頭子derek和他手下tidy又開始忙乎了。a國在海岸線沿直線布置了n個工兵營地,derek和tidy的任務就是要監視這些工兵營地的活動情況。由於採取了某種先進的監測手段,所以每個工兵營地的人數c國都掌握的一清二楚,每...
線段樹 單點更新模板題
線段樹應該是資料結構中的一種吧,說白了,他就是一種工具,只要你學會了他,那麼你就可以在以後的學習中去用它。他的大致用法,就是把乙個一維陣列改變成乙個樹的結構,而且這個樹還是乙個完全二叉樹 上述圖就是把乙個1 8的區間變成了乙個二叉樹的結構,為什麼我們要這樣幹呢?這怎麼說呢?其實我也說不清楚。因為能力...