樹——線段樹區間修改

上兩篇博文簡單說了線段樹,線段樹節點修改非常簡單,不過區間修改有一定難度,不過也是線段樹中的簡單環節,接下來看一個實例。

#1078 : 線段樹的區間修改

時間限制:10000ms

單點時限:1000ms

內存限制:256MB

描述

對於小Ho表現出的對線段樹的理解,小Hi表示挺滿意的,但是滿意就夠了麼?於是小Hi將問題改了改,又出給了小Ho:

假設貨架上從左到右擺放了N種商品,並且依次標號爲1到N,其中標號爲i的商品的價格爲Pi。小Hi的每次操作分爲兩種可能,第一種是修改價格——小Hi給出一段區間[L, R]和一個新的價格NewP,所有標號在這段區間中的商品的價格都變成NewP。第二種操作是詢問——小Hi給出一段區間[L, R],而小Ho要做的便是計算出所有標號在這段區間中的商品的總價格,然後告訴小Hi。

那麼這樣的一個問題,小Ho該如何解決呢?

提示:推動科學發展的除了人的好奇心之外還有人的懶惰心!

輸入

每個測試點(輸入文件)有且僅有一組測試數據。

每組測試數據的第1行爲一個整數N,意義如前文所述。

每組測試數據的第2行爲N個整數,分別描述每種商品的重量,其中第i個整數表示標號爲i的商品的重量Pi。

每組測試數據的第3行爲一個整數Q,表示小Hi進行的操作數。

每組測試數據的第N+4~N+Q+3行,每行分別描述一次操作,每行的開頭均爲一個屬於0或1的數字,分別表示該行描述一個詢問和一次商品的價格的更改兩種情況。對於第N+i+3行,如果該行描述一個詢問,則接下來爲兩個整數Li, Ri,表示小Hi詢問的一個區間[Li, Ri];如果該行描述一次商品的價格的更改,則接下來爲三個整數Li,Ri,NewP,表示標號在區間[Li, Ri]的商品的價格全部修改爲NewP。

對於100%的數據,滿足N<=10^5,Q<=10^5, 1<=Li<=Ri<=N,1<=Pi<=N, 0<Pi, NewP<=10^4。

輸出

對於每組測試數據,對於每個小Hi的詢問,按照在輸入中出現的順序,各輸出一行,表示查詢的結果:標號在區間[Li, Ri]中的所有商品的價格之和。

  • 樣例輸入

  • 10
    4733 6570 8363 7391 4511 1433 2281 187 5166 378 
    6
    1 5 10 1577
    1 1 7 3649
    0 8 10
    0 1 4
    1 6 8 157
    1 3 4 1557
  • 樣例輸出

  • 4731
    14596


AC代碼:線段樹區間修改,區間求和,在線段樹節點修改的基礎上加一個value記錄標記。

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#include<vector>

#include<list>

#include<iterator>

#include<string>

#include<stack>

using namespace std;

const int MAX = 100000100;


struct NODE {

int value, left, right, sum;

}node[MAX];


void BuildTree(int n, int left, int right) {

node[n].left = left;

node[n].right = right;

node[n].value = 0;

if (left == right)

{

scanf("%d", &node[n].sum);

return;

}

int mid = (left + right) >> 1;

BuildTree(n << 1, left, mid);

BuildTree((n << 1) | 1, mid + 1, right);

node[n].sum = node[n << 1].sum + node[(n << 1) | 1].sum;

}


void PushDown(int n) {

if (node[n].value){

node[n << 1].sum = (node[n << 1].right - node[n << 1].left + 1)*node[n].value;

node[n << 1 | 1].sum = (node[n << 1 | 1].right - node[n << 1 | 1].left + 1)*node[n].value;

node[n << 1].value = node[n << 1 | 1].value = node[n].value;

node[n].value = 0;

}

}


int FindTree(int n, int begin, int end) {

int p1 = 0,p2 = 0;

if (node[n].left >= begin&&node[n].right <= end)

return node[n].sum;

PushDown(n);

if (begin <= node[n << 1].right)

p1 = FindTree(n << 1, begin, end);

if (end >= node[(n << 1) | 1].left)

p2 = FindTree((n << 1) | 1, begin, end);

node[n].sum = node[n << 1].sum + node[n << 1 | 1].sum;

return p1 + p2;

}


void UpdateTree(int n, int left, int right, int val) {

if (node[n].left >= left && node[n].right <= right)

{

node[n].sum = (node[n].right - node[n].left + 1)*val;

node[n].value = val;

return;

}

PushDown(n);

if (left <= node[n << 1].right)

UpdateTree(n << 1, left,right,val);

if (right >= node[(n << 1) | 1].left)

UpdateTree((n << 1) | 1,left,right,val);

node[n].sum = node[n << 1].sum + node[(n << 1) | 1].sum;


}


int main()

{

int N;

int m;

int s, l, r, v;

while (~scanf("%d", &N))

{

BuildTree(1, 0, N - 1);

scanf("%d", &m);

for (int i = 0; i < m; i++)

{

scanf("%d %d %d", &s, &l, &r);

if (s == 0)

printf("%d\n", FindTree(1, l - 1, r - 1));

if (s == 1)

{

scanf("%d", &v);

UpdateTree(1, l - 1, r -1,v);

}

}

}

return 0;

}


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