P3372 模板 線段樹 1

2021-09-13 20:16:51 字數 3530 閱讀 1809

線段樹學習

這個題來看,線段樹分為建樹,更新,查詢。

1.建樹

void

build

(ll p,ll l,ll r)

ll mid=

(l+r)

>>1;

build

(lson

(p),l,mid)

;build

(rson

(p),mid+

1,r)

;push_up_sum

(p);

}void

push_up_sum

(ll p)

這段**的意義是,先將每個節點的lazytag標記置為0,然後再遞迴建樹。裡面的push_up_sum代表這個線段樹記錄的是區間的和.

2.更新

inline

void

f(ll p,ll l,ll r,ll k)

inline

void

push_down

(ll p,ll l,ll r)

inline

void

update

(ll p,ll l,ll r,ll x,ll y,ll k)

push_down

(p,l,r)

;//如果l,r有更新的,那就更新

ll mid=

(r+l)

>>1;

if(x<=mid)

update

(lson

(p),l,mid,x,y,k);if

(y>mid)

update

(rson

(p),mid+

1,r,x,y,k)

;// printf("777\n");

push_up_sum

(p);

//把子節點更新的push上來.

}

lazytag的主要意義是,p節點的值更新後,tag[p]是更新p節點子節點的資訊。如果後續沒有查詢p的子節點,那麼就不用更新p的子節點。這樣的好處就是大大減少了時間複雜度。

而push_down函式就要在每一次使用p子節點的時候呼叫,用來更新p的子節點。只更新下一層

f函式是用k值更新p節點所對應的[l,r]區間,並用tag[p]儲存資訊。只更新本層

update函式是已知要對[x,y]的每個元素更新k,而利用傳參可以知道目前更新目標是p節點對應的[l,r]

1.如果[l,r]包含於[x,y],那麼這個區間就需要更新,呼叫f函式

2.如果[l,r]不包含與[x,y],此時要呼叫子節點了,所以先呼叫push_down函式。然後在有交集的情況下,從左邊區間和右邊區間分別尋找[x,y]的子區間,並更新。

3.查詢

這個和更新差不多,不再贅述

ll query

(ll p,ll l,ll r,ll x,ll y)

ll mid=

(l+r)/2

;// printf("%d\n",mid);

// printf("7\n");

push_down

(p,l,r);if

(x<=mid) res+

=query

(lson

(p),l,mid,x,y);if

(y>mid) res+

=query

(rson

(p),mid+

1,r,x,y)

;return res;

}

完整**

#include

using namespace std;

#define mxn 1000005

typedef

long

long ll;

ll dat[mxn<<1]

;ll tag[mxn<<1]

,a[mxn]

;//tag[p]==0,說明這個節點不需要被修改.tag[p]==k,說明這個節點的子區間需要被加上自變數為k的影響

inline ll lson

(ll rt)

inline ll rson

(ll rt)

void

push_up_sum

(ll p)

void

build

(ll p,ll l,ll r)

ll mid=

(l+r)

>>1;

build

(lson

(p),l,mid)

;build

(rson

(p),mid+

1,r)

;push_up_sum

(p);

}void

push_up_min

(ll p)

inline

void

f(ll p,ll l,ll r,ll k)

inline

void

push_down

(ll p,ll l,ll r)

inline

void

update

(ll p,ll l,ll r,ll x,ll y,ll k)

push_down

(p,l,r)

;//如果l,r有更新的,那就更新

ll mid=

(r+l)

>>1;

if(x<=mid)

update

(lson

(p),l,mid,x,y,k);if

(y>mid)

update

(rson

(p),mid+

1,r,x,y,k)

;// printf("777\n");

push_up_sum

(p);

//把子節點更新的push上來.

}ll query

(ll p,ll l,ll r,ll x,ll y)

ll mid=

(l+r)/2

;// printf("%d\n",mid);

// printf("7\n");

push_down

(p,l,r);if

(x<=mid) res+

=query

(lson

(p),l,mid,x,y);if

(y>mid) res+

=query

(rson

(p),mid+

1,r,x,y)

;return res;

}int

main

(void

)// printf("111");

build(1

,1,n);

while

(m--)if

(a1==2)

}// system("pause");

return0;

}

P3372 模板 線段樹 1

題 include includeusing namespace std typedef long long ll ll n,m,ans,x,y,op,val 因為下面有的函式需要用到x,y,val值,懶得傳參,故直接寫為全域性變數 const int n 100000 struct nodetre...

P3372 模板 線段樹 1

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

P3372 模板 線段樹 1

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