SDUT OJ 數組計算機(線段樹)

學長推薦了這個博客詳細的介紹了線段樹的建立、查找、更新;

數組計算機

Time Limit: 1000 ms Memory Limit: 65536 KiB

Submit Statistic

Problem Description

bLue 有一個神器的機器,這個機器可以讀入一個數組,並按照用戶要求快速地進行數組的處理和計算,它支持如下兩種操作:

  • 操作 1:把數組中第 p 個元素的值增加 v。
  • 操作 2:計算數組中 [l, r] 區間內所有數的和。

這個機器就是這麼的神奇,但是 bLue 的計算機壞掉了,你能幫他修一下嗎?

Input

輸入數據有多組(數據組數不超過 20),到 EOF 結束。

對於每組數據:

  • 第 1 行輸入一個整數 n (1 <= n <= 10^5),表示數組中元素的個數。
  • 第 2 行輸入 n 個用空格隔開的整數 ai (1 <= ai <= 10^10),表示初始輸入到計算機中的數組。
  • 第 3 行輸入一個整數 q (1 <= q <= 50000),表示用戶的操作次數。
  • 接下來 q 行,每行輸入先輸入 1 個整數,表示操作類型,根據不同的操作類型:
    • 如果類型爲 1,則緊接着輸入 2 個用空格隔開的整數 p (1 <= p <= n) 和 v (1 <= v <= 10^10),表示要把數組中第 p 個數的值增加 v。
    • 如果類型爲 2,則緊接着輸入 2 個用空格隔開的整數 l, r (1 <= l <= r <= n),表示要計算區間 [l, r] 內所有數的和(數組下標從 1 開始)。

Output

對於每組數據中的每次類型爲 2 的操作,輸出 1 行,包含一個整數,表示計算出的和。

Sample Input

5
1 2 3 4 5
5
2 1 2
2 1 5
1 4 10
2 4 5
2 1 5

Sample Output

3
15
19
25

補一波學長的總結:

  • 首先明確一點,線段樹是一顆完全二叉樹,然後建樹的時候用數組比較方便。
  • 假設根節點下標是n,那麼他的左兒子下標是n×2+1,右兒子下標是n×2+2。
  • 這裏有個細節是數組是開的結構體數組,因爲一個節點有時候要儲存好幾個信息,這裏我把維護的區間也儲存起來了,方便查詢的時候調用。
  • 建樹的時候遞歸建樹就可以。
  • 查詢的時候,這裏分兩種情況:如果查詢區間與當前節點的區間無交集,那麼返回。如果查詢區間與當前節點的區間有交集,那麼把查詢區間更新爲這個交集。(具體爲什麼,可以畫圖模擬一下就知道了)
  • 最後當前節點是葉子節點的話,就直接返回當前節點的值,否則繼續查詢當前節點的左右子樹並返回兩者返回值的和。
  • 更新節點值的時候相當於二分查找,直到找到需要添加值的葉子節點。這裏需要注意的是,查詢過程中,如果沿途上的節點的區間包含要更新的節點的話,順便把這個節點也更新掉。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

struct node
{
    int l, r;
    long long int data;
};

struct node tree[1234567];
long long int Begin[1234567];


void Buildtree( int root, int l, int r )
{
    tree[root].l = l;
    tree[root].r = r;
    if( l == r )
        tree[root].data = Begin[l];
    else
    {
        int mid = ( l + r ) / 2;
        Buildtree( root * 2 + 1, l,   mid );
        Buildtree( root * 2 + 2, mid+1, r );
        tree[root].data = tree[root * 2 + 1].data + tree[root * 2 + 2].data;
    }
}


long long int Query ( int root, int l, int r )
{
    int i = tree[root].l, j = tree[root].r;
    if( i > r || j < l )
        return 0;

    l = max( l, i );
    r = min( r, j );
    if( i == l && j == r )
        return tree[root].data;

    return Query( root * 2 + 1, l, r ) + Query( root * 2 + 2, l, r );
}

void Updata ( int root, long long int pos, long long int data )
{
    int l = tree[root].l, r = tree[root].r;
    if( l > pos || r < pos )
        return;

    tree[root].data += data;

    if( l == r )
        return;

    Updata( root * 2 + 1, pos, data );
    Updata( root * 2 + 2, pos, data );
}


int main()
{
    int n;
    while( ~scanf("%d", &n) )
    {
        memset( tree, 0, sizeof( tree ));
        memset( Begin, 0, sizeof(Begin));
        int i;
        for( i=0; i<n; i++ )
            scanf("%lld", &Begin[i]);
        Buildtree( 0, 0, n-1 );


        int q;
        scanf("%d", &q);
        while( q-- )
        {
            int type;
            long long int x, y;
            scanf("%d %lld %lld", &type, &x, &y);
            if( type == 1 )
                Updata( 0, x-1, y );
            if( type == 2 )
                printf("%lld\n", Query(0, x-1, y-1));
        }
    }
    return 0;
}

 

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