1. 程式人生 > >樹狀陣列(區間更新)差分思想

樹狀陣列(區間更新)差分思想

已知一個數列,你需要進行下面兩種操作:

1.將某區間每一個數數加上x

2.求出某一個數的和

題:

第一行包含兩個整數N、M,分別表示該數列數字的個數和操作的總個數。

第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。

接下來M行每行包含2或4個整數,表示一個操作,具體如下:

操作1: 格式:1 x y k 含義:將區間[x,y]內每個數加上k

操作2: 格式:2 x 含義:輸出第x個數的值

輸出格式:

輸出包含若干行整數,即為所有操作2的結果。

輸入輸出樣例

輸入樣例#1: 複製

5 5
1 5 4 2 3
1 2 4 2
2 3
1 1 5 -1
1 3 5 7
2 4

輸出樣例#1: 複製

6
10

說明

時空限制:1000ms,128M

資料規模:

對於30%的資料:N<=8,M<=10

對於70%的資料:N<=10000,M<=10000

對於100%的資料:N<=500000,M<=500000

樣例說明:

故輸出結果為6、10

關於差分:

設陣列a[]={1,6,8,5,10},那麼差分陣列b[]={1,5,2,-3,5}

也就是說b[i]=a[i]-a[i-1];(a[0]=0;),那麼a[i]=b[1]+....+b[i];(這個很好證的)。//理解這裡很重要

假如區間[2,4]都加上2的話

a陣列變為a[]={1,8,10,7,10},b陣列變為b={1,7,2,-3,3};

發現了沒有,b陣列只有b[2]和b[5]變了,因為區間[2,4]是同時加上2的,所以在區間內b[i]-b[i-1]是不變的.

所以對區間[x,y]進行修改,只用修改b[x]與b[y+1]:

b[x]=b[x]+k;b[y+1]=b[y+1]-k;

這個題目是樹狀陣列的一個拓展,在樹狀陣列中可以用前 i 項的和來表示第 i 個數.

那麼當對 x ~ y 的區間進行修改的時候需要在樹狀陣列中的第 x 個位置 + k, 第 y + 1 個位置 -k

這樣便維護了這個樹狀陣列

輸出時候直接輸出查詢即可

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <list>
#include <deque>
#include <vector>
#include <map>
#define LL long long
int lowbit(int x)
{
    return x&(-x);
}
const int MAXN =1e6+7;
const long long MAX=0x7f7f7f3f;
using namespace std;
void read(int &x){
	char ch = getchar();x = 0;
	for (; ch < '0' || ch > '9'; ch = getchar());
	for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}
long long  arr[MAXN]={0},c[MAXN]={0};
long long  n,m,k;
long long  sum(long long  x,long long  c[])
{
   long long ret=0;
    for(int i=x;i>0;i-=lowbit(i))
    {
        ret+=arr[i];
        //ret+=c[i];
    }
    return ret;
}/*
void updata(int x,int val,int n)
{
   for(int i=x;i<=n;i+=lowbit(i))
    {
        c[i]+=val;
       // x+=lowbit((x));
    }
}*/
void updata(long long x,long long  val)
{
   // int i=l;
    for(int i=x;i<=n;i+=lowbit(i))
    {
       // c[i]+=val;
        arr[i]+=val;
    }
}
int main()
{
    ios::sync_with_stdio(false);

   // int n,m,k;
    cin>>n>>m;
    long long num;
    long long last=0,now;
    for(int i=1;i<=n;i++)
    {
       // cin>>arr[i];
        //updata(i,arr[i]);
        cin>>now;
        updata(i,now-last);
        last=now;
    }
    while(m--)
    {
        int l,r,val;
        int x;
        cin>>k;
        if(k==1)
        {
            cin>>l>>r>>val;
            updata(l,val);
            updata(r+1,-val);
        }
        else
        {
            cin>>x;
            //int ans=sum(r,c,n)-sum(l-1,c,n);
           // cout<<sum(r,c,n)<<" "<<sum(l,c,n)<<endl;
           cout<<sum(x,c)<<endl;
        }
    }
    return 0;
}

相關推薦

陣列區間更新思想

已知一個數列,你需要進行下面兩種操作: 1.將某區間每一個數數加上x 2.求出某一個數的和 題: 第一行包含兩個整數N、M,分別表示該數列數字的個數和操作的總個數。 第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。 接下來M行每行包含2或

Color the ball 陣列區間更新,單點查詢

N個氣球排成一排,從左到右依次編號為1,2,3....N.每次給定2個整數a b(a <= b),lele便為騎上他的“小飛鴿"牌電動車從氣球a開始到氣球b依次給每個氣球塗一次顏色。但是N次以後lele已經忘記了第I個氣球已經塗過幾次顏色了,你能幫他算出每個氣球被塗過幾次顏色嗎? Inpu

陣列區間修改單點查詢洛谷:陣列2

模版和單點修改區間查詢差不多 樹狀陣列(單點修改區間查詢) https://blog.csdn.net/johnwayne0317/article/details/84927585 然後用到了差分陣列 https://blog.csdn.net/johnwayne0317/a

陣列區間修改,單點查詢

這裡介紹樹狀陣列+差分思想,算是對下面大神的補充吧。 何為差分現在我們有一個從小到大的數列a[] a{1,3,6,8,9}; 然後還有一個差分陣列b[] b{1,2,3,2,1} 相信某些小夥伴已經看

二維陣列區間修改,單點查詢

好像不管是幾維都和一維原理差不多,多了一個維度也就多了一層迴圈而已(QAQ) #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath&g

淺談陣列解析+模板

也不知道是什麼時候開始,對於曾經學過的演算法都不太用了 遇到區間修改,區間最值就知道用線段樹,什麼樹狀陣列啊,st表啊都忘得差不多了 最近幾次模考被卡翻了,於是又想起這些老朋友 來填個坑   首先我們要明確一點,樹狀陣列只能維護求和,不能維護區間最值 樹狀陣列利用了分治的思想,層數為

陣列未完成

    (建議邊對著圖邊看解釋)    背景:若線上地修改數列裡某個數的值,其維護【字首和】的複雜度太高   樹狀陣列c性質: 1、c[i]的管轄區間以a[i]結尾,從某種意義來說,c[i]與a[i]一一對應 2、c[i]的管轄區間長2^k,k

陣列區間更新區間查詢

對於區間修改、區間查詢這樣的簡單問題,打一大堆線段樹確實是不划算,所以學習下區間查詢+區間修改的樹狀陣列   設原陣列是a[n],差分陣列c[n],c[i]=a[i]-a[i-1], 那麼明顯地a[i]=sigma (c[i]),如果想要修改a[i]到a[j](比如+v),只需

陣列區間更新與查詢

具體思路:由於樹狀陣列裸的模板只能通過陣列求區間和,而對於區間的更新的查詢無法實現,所以通過多個數組進行輔助。 具體公式,通過三個陣列實現。第一個陣列記錄第一組的字首和。然後如果是更新的話,舉個例子,一共有10個數,1~n.在5 8 之間每一個數加3,也就是總的和在原來的基礎上上加

【專題】陣列完整版

傳統陣列(共n個元素)的元素修改和連續元素求和的複雜度分別為O(1)和O(n)。樹狀陣列通過將線性結構轉換成偽樹狀結構(線性結構只能逐個掃描元素,而樹狀結構可以實現跳躍式掃描),使得修改和求和複雜度均為O(lgn),大大提高了整體效率。 給定序列(數列)A,我們設一個數組C滿足 C[i] = A[i–

陣列模板區間更新 區間詢問

14、樹狀陣列 (1)、單點增減+區間求和 思路:C[x]表示該點的元素:sum(x)=C[1]+C[2]+……C[x]int arr[MAXN]; inline int sum(int x){int res=0;while(x)res+=arr[x],x-=lowbit(

陣列區間加法

應用差分原理,實現樹狀陣列區間加法 差分:a區間[1, 2, 3, 4, 5],則差分割槽間為[1, 1, 1, 1, 1]即bn = an - an-1,an = b1 +…+ bn 如果對區間[2, 4]都加上2,則a[1, 5, 6, 7, 5], 差分割槽間[1, 4, 1,

陣列單點更新區間更新,二維陣列poj2155區間更新,單點查詢已加入區間修改區間查詢

普通的樹狀陣列C[i]=a[i]+a[i-1]+...a[i-2^k+1]+...+a[1]; 但是所有樹狀陣列都是向上更新,向下求和。 1)、單點增減+區間求和 思路:C[x]表示該點的元素:sum(x)=C[1]+C[2]+……C[x] [cpp] view p

hdu1556 Color the ball 陣列應用型別二區間更新 單點求值】

題目連線:http://acm.hdu.edu.cn/showproblem.php?pid=1556 Problem Description N個氣球排成一排,從左到右依次編號為1,2,3....N.每次給定2個整數a b(a <= b),lele便為騎上他

敵兵佈陣 陣列應用型別一【單點更新區間求和】

題目連線:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Problem Description C國的死對頭A國這段時間正在進行軍事演習,所以C國間諜頭子Derek和他手下Tidy又開始忙乎了。A國在海岸線沿直線佈置了N個

【模板】陣列

題目描述 如題,已知一個數列,你需要進行下面兩種操作: 1.將某區間每一個數數加上x 2.求出某一個數的和 輸入輸出格式 輸入格式: 第一行包含兩個整數N、M,分別表示該數列數字的個數和操作的總個數。 第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值

神奇的內附陣列的一點擴充套件

差分法是我們所用的一個強力的武器! 有這把武器你就可以統治世界。。。 一個大佬曾經講過,一但碰到區間修改的題,就要優先考慮差分。 目錄 普通差分法 差分套差分(二階差分) 高階差分 樹上差分(點的意義與邊的意義) 例題 普通差分法

陣列單點修改區間查詢

lowbit(重要!) lowbit是用來取出二進位制中最低位數的1所代表的二進位制的值。 只需要記下程式碼就行了 int lowbit(int x){ return x&(-x); } add單點修改字首和 將一個樹的最子節點修改,則其父節點也需要更改,父

Non Super Boring Substring —— 馬拉車+陣列求不包含迴文串區間的個數

You’ll be given a string S​ and an integer K​. You have to find the number of non super-boring substring inside S​. A substring is

POJ 2481 Cows 陣列 單點更新 每個集合是幾個集合的真子集

Description Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensi