ACM暑期集訓4

2021-08-21 17:51:06 字數 3382 閱讀 2314

今天主要學習了線段樹,樹狀陣列,st表,差分,分塊和樹剖(好吧,這個已經沒聽懂了)

1.線段樹

線段樹涉及許多應用和思想,以下是今天所學

線段樹主要用於處理一段連續區間的插入,查詢,統計,查詢等操作。

複雜度:設區間長度是n,所有操作的複雜度是logn級別。

性質:線段樹是平衡的2叉樹,最大深度logn(n為線段樹所表示區間的長度)

樹中的每乙個節點代表對應乙個區間(葉子節點是乙個點……)

每個節點(所代表的區間)完全包含它的所有子孫節點 對於任意兩個節點(所代表的區間):要麼完全包含,要麼互不相交。

1)單點修改,區間查詢

先來道裸題

有個長度為n的序列a,m(m<=100000)次詢問, ·

有兩種操作: ·  

1.詢問: 詢問區間l到r的數的和 ·

2.修改: 將序列中下標為p的的元素的值加v ·

要求輸出每一次詢問的結果…… (n<=100000,m<=100000)

直接上模板**(解釋見註解)

struct segtree[2*n];

void build(int p,int l,int r) //建樹,從頭結點(1,l,r)開始

void add(int p,int x,int y) //單點修改,將x出的點加y,可將讀入視為修改,從(1,i,y)開始

int mid=(tree[p].l+tree[p].r)>>1;

if(x<=mid) add(p<<1,x,y);

else add(p<<1|1,x,y);

tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;

}int ask(int p,int l,int r) //詢問區間(l,r)元素的和

2)區間修改,區間求和,lazy思想

老樣子,來道裸題

有個長度為n的序列a,m次詢問

請實現兩種操作:

1. 詢問[l,r]的區間和

2.修改:將[l,r]的元素全部加x   n<=100000,m<=100000

先來介紹lazy思想:

記錄每乙個線段樹節點的變化值,當這部分線段的一致性被破壞我們就將這個變化值傳遞給子區間,大大增加了線段樹的效率。

在此通俗的解釋lazy的意思,比如現在需要對[a,b]區間值進行加c操作,那麼就從根節點[1,n]開始呼叫update函式進行操作,如果剛好執行到乙個子節點,它的節點標記為rt, 這時我們可以一步更新此時rt節點的sum[rt]的值,sum[rt] += c* (r - l + 1),更這個節點的lazy標記。注意關鍵的時刻來了,如果此時按照常規的線段樹的update操作,這時候還應該更新rt子節點的sum值,而lazy思想恰恰是暫時不更新rt子節點的sum值,到此就return,直到下次需要用到rt子節點的值的時候才去更新,這樣避免許多可能無用的操作,從而節省時間。

#define l o<<1

#define r o<<1|1

#define ll long long

#define max 100000

struct node

tree[max<<2];

void push_up(int o)

void build(int o,int l,int r)

int mid = (l + r) >> 1;

build(l,l,mid);

build(r,mid+1,r);

push_up(o);

}void push_down(int o)

}void add(int o,int l,int r,int lazy)

push_down(o);

int mid = (tree[o].l + tree[o].r) >> 1;

if (mid >= r)

add(l,l,r,lazy);

else if (l > mid)

add(r,l,r,lazy);

else

push_up(o);

}ll ask(int o,int l,int r)

}

對於其他的單點/區間修改,區間最值其實主要對push_down和其他小細節修改即可

3)合併思想

來道裸題

單點修改,查詢區間最大連續子段和 (n<=100000,m<=100000)

分析:定義lm為區間的左連續區間的最大和,rm為區間的右連續區間的最大和

mx為區間的最大子段和,sum為區間和

對於乙個區間[l,r] mx[l,r]=max(max(mx[l,mid],mx[mid+1]),rm[l,mid]+lm[mid+1,r]])

那麼只需維護這三個量即可。

lm[l,r]=max(lm[l,mid],sum[l,mid]+lm[mid+1,r])

rm[l,r]=max(rm[mid+1,r],rm[l,mid]+sum[mid+1,r])

單點修改很容易解決了 查詢時,需要返回三元組(mx,lm,rm),即可維護答案。

2.樹狀陣列

主要解決動態區間,字首和的問題,即可以實現單點修改,詢問字首和

利用樹狀陣列+差分,也可以解決單點修改詢問區間和,區間加法詢問單點值,甚至區間加區間求和也可以做。詳細應用見傳送門

常數小,**短,二維也很容易實現

還有一些其他問題也可以通過樹狀陣列來解決,比如區間。所以一般用線段樹就夠了,樹狀陣列能做的,線段樹一定能做,很少有出題人卡這個(所以還是有的),但是又短又小又快。。。能用為啥不用

樹狀陣列可以很容易的解決最長上公升子串行,還有一些高維偏序問題一般會套用樹狀陣列,應用還有很多。

int bit[1000],n;

void add(int x,int val) //a[i]+=val 單點修改

int ask(int x) //sum[1~x]

3.st表

主要解決靜態區間,最值問題,即沒有修改,只有詢問區間最值

容易推廣到二維

倍增的思想很重要!

線段樹預處理是o(nlogn),單次查詢o(logn),空間o(n)

st表預處理是o(nlogn),單次查詢o(1),空間o(nlogn)

int log[maxn],f[17][maxn];

int ask(int x,int y)

5.後續知識點(現在先了解吧)

線段樹相關:可持久化線段樹,線段樹套bulabula,和其他各種東西結合,zkw線段樹

其他常用資料結構:trie,樹剖,splay,hash表,左偏樹,莫隊,lct,k-d tree,treap,可持久化***...

c++的pb_ds庫:封裝了很多資料結構,比如:平衡樹,雜湊表,字典樹,堆...

ACM暑期集訓2

今天主要學習了線性dp和揹包問題以及快速冪。1.整數快速冪 這個直接粘上 int qpow int x,int n res res res n n 1 return ans 2.矩陣快速冪 主要就是將整數快速冪的乘法運算換做矩陣的乘法 下面的 是方陣的快速冪 const int n 10 int t...

ACM暑期集訓5

今天主要學習力圖論基礎和最短路徑 1.圖論基礎 1 鄰接矩陣存圖 w i j 表示以ij為頂點的邊的權值 const int n 105,inf 9999999 int dis n w n n vis n n,m 鄰接矩陣存圖 for int i 1 i n i for int i 0 i2 鄰接表...

ACM暑期集訓12

今天學了字尾陣列,感覺好難理解,只能搬ppt,粘模板了 1 字尾 suffix i 為從下標i開始的字尾 string abcdef suffix 1 bcdef suffix 2 cdef 什麼是字尾陣列?把乙個字串的所有字尾按字典序進行排序。字尾陣列sa i 表示排名為i的字尾下標是什麼,rk ...