閱讀497 返回首頁    go 阿裏雲 go 技術社區[雲棲]


算法訓練-線段樹

WIKIOI-1080 線段樹練習

題目描述 Description
一行N個方格,開始每個格子裏都有一個整數。現在動態地提出一些問題和修改:提問的形式是求某一個特定的子區間[a,b]中所有元素的和;

修改的規則是指定某一個格子x,加上或者減去一個特定的值A。現在要求你能對每個提問作出正確的回答。1≤N<100000,,提問和修改的總數

m<10000條。

輸入描述 Input Description
輸入文件第一行為一個整數N,接下來是n行n個整數,表示格子中原來的整數。接下一個正整數m,再接下來有m行,表示m個詢問,第一個整數

表示詢問代號,詢問代號1表示增加,後麵的兩個數x和A表示給位置X上的數值增加A,詢問代號2表示區間求和,後麵兩個整數表示a和b,表示

要求[a,b]之間的區間和。

輸出描述 Output Description
共m行,每個整數

樣例輸入 Sample Input
6
4 5 6 2 1 3
4
1 3 5
2 1 4
1 1 9
2 2 6
樣例輸出 Sample Output
22
22
數據範圍及提示 Data Size & Hint
1≤N≤100000, m≤10000 。

 

 

 

 

本題的目的是訓練線段樹的構造
AC代碼:

#include<stdio.h>
#include<string.h>
struct node//構造線段樹需要的結構體 
{
   int l,r;
   int sum;
}a[400010];//線段樹需要開2*N以上的空間,此處最容易出錯!!
void Bulid(int n,int l,int r)//創建一顆範圍為[l,r]的線段樹 
{
     a[n].l=l;//左邊界賦值 
     a[n].r=r;//右邊界賦值 
     a[n].sum=0;//總和初始化 
     if(l==r)//如果左右孩子相等,創建結束 
     return;
     Bulid(2*n,l,(l+r)/2);//創建左孩子 
     Bulid(2*n+1,(l+r)/2+1,r);//創建右孩子 
}
void Insert(int n,int v,int num)//向線段樹插入位置為v的權值num 
{
     a[n].sum+=num;//更新總和 
     if(a[n].l==a[n].r)//若左右邊界相等,結束更新 
     return;
     if(v<=(a[n].l+a[n].r)/2)//位置小於中間值,往左子樹插入,反之去右子樹 
     Insert(n*2,v,num);
     else
     Insert(n*2+1,v,num);
}
void Change(int n,int v,int num)//改變線段樹中位置為v的權值(加上num) 
{
     if(v==a[n].l&&v==a[n].r)//左右子樹相同,執行更新 
     {
        a[n].sum+=num;
        return;
     }
     else
     if(v<=(a[n].l+a[n].r)/2)//位置小於中間值,往左子樹更新,反之去右子樹
     Change(n*2,v,num);
     else
     Change(n*2+1,v,num);
     a[n].sum=a[n*2].sum+a[n*2+1].sum;//由於上麵的遞歸已經修改了權值,更新總值 
}
int Sum(int n,int l,int r)//計算位置範圍在l、r內數權值的總和 
{
     if(l==a[n].l&&r==a[n].r)//邊界等於左右子樹,輸出本位置的權值和 
     return a[n].sum;
     if(r<=(a[n].l+a[n].r)/2)//右邊界小於中間值,往左子樹尋找總和 
     return Sum(n*2,l,r);
     else
     if(l>(a[n].l+a[n].r)/2)//左邊界大於中間值,往右子樹尋找總和 
     return Sum(n*2+1,l,r);
     else//不滿足上麵兩個條件,i、r則在 a[n].l與a[n].r中間,那麼分別求和 
     return Sum(n*2,l,(a[n].l+a[n].r)/2)+Sum(n*2+1,(a[n].l+a[n].r)/2+1,r);
     
}
int main()
{
    int i,j,n,m,Q,L,R;
    scanf("%d",&n);
    Bulid(1,1,n);
    for(i=1;i<=n;i++)
    {
       scanf("%d",&m);
       Insert(1,i,m);
    }
    scanf("%d",&m);
    while(m--)
    {
       scanf("%d %d %d",&Q,&L,&R);
       if(Q==1) 
       {
          Change(1,L,R);
       } 
       else if(Q==2)
       {
          printf("%d\n",Sum(1,L,R));
       }
    }
    return 0;
}

本代碼為原創,轉載請注明出處!

最後更新:2017-04-03 12:55:38

  上一篇:go Oracle Partition 分區詳細總結
  下一篇:go hi3531的i2c部分