資料結構-黃洛天

lupengheyyds發表於2024-07-14

資料結構-黃洛天

A - 冰火戰士

題面

支援$Q$次兩種操作,

  • 新增一個三元組 $(w,a,b),w\in{0,1}$
  • 撤回第 $k$ 此操作,此操作保證為報名資訊

每次操作後,求

$$
\max_{x}\min(\sum_{w_i=0,a_i\le x}b_i,\sum_{w_i=1,a_i\ge x}b_i)
$$

以及取到最值的最大的 $x$。

$1\le Q\le 1\times 10^6,1\le x\le 2\times 10^9,不存在相同的三元組$

題解

有一個很顯然的$\mathcal O(n\log^2n)$ 做法,即對每個 $w\in{0,1}$ 開一個樹狀陣列,每次二分查詢 $x$,並判定 $\sum_{w_i=0,a_i\ge x}b_i-\sum_{w_i=1,a_i\le x}b_i$ 的正負,使其最接近 $0$,確定了值之後,再倍增求得 $x$ 。

考慮最佳化,我們發現,樹狀陣列上的 $p$ 號節點儲存的恰為 $[p-\operatorname{lowbit}(p)+1,p]$,利用這一點,我們可以在倍增的過程中不斷同步累加樹狀陣列中的值,從而最佳化掉一個 $\log$。

當從 $p$ 倍增到 $p+2^i$ 次方時,由於$\operatorname {lowbit}(p)>2^i$ ,所以我們只需要加上 $bitr[p+2^i]$ 檢視是否合法即可。

複雜度 $\mathcal O(n\log n)$。

方法

  • 倍增同時 $O(1)$ 查詢樹狀陣列中的值。

程式碼

連結

B - Fenwick Tree

題面

有一個長度為 $n$ 的樹狀陣列,給出在進行了若干次單調修改操作後每個位置儲存的值是否非 $0$,求最少進行了幾次修改操作。

$1\le n\le 10^5$

題解

每次修改相當於給某個點到根加一個數字。

我們從低向上考慮整個樹,依次判斷是否要給當前節點操作。假設他有 $k$ 個兒子是大於 $0$ 的。

  • $k = 0$,子樹內所有操作對於我的影響是 $0$.

  • $k = 1$,子樹內所有操作對於我的影響一定非 0

  • $k > 1$,子樹內所有操作對於我的影響是任意的。

因此只有 $k = 0$ 且目標是 $1$ 的時候需和 $k = 1$ 且目標是 $0$ 的時候要進行操作。 時間複雜度 $\mathcal O(n)$。

方法

  • 考慮貢獻

    整體考慮子樹對父親的貢獻。

C - Traveling in Cells

題面

有 $n$ 個二元組 $(c,v)$ ,支援 $q$ 次三種操作

  • $1\ p\ x$:將 $c_p$ 修改為 $x$

  • $2\ p\ x$:將 $v_p$ 修改為 $x$

  • $3\ p\ k\ a_{1\sim k}$:求 $\max\limits_{p\in [l,r]}\sum\limits_{\forall i\in[l,r],c_i\in{a_1,a_2,\cdots,a_k}}v_i$

$1\le n\le 10^5,1\le q\le 10^5,\sum k\le 10^6$

題解

對於每一個 $c$ 建立一顆線段樹維護區間個數,前兩個操作就是單點修改,第三個操作結合樹狀陣列求解。

對於第三個操作,本質上是找到左與右第一個的沒有出現在 $a$ 中的 $c$ ,只需要看這些顏色是否鋪滿一個區間便是,程式碼如下:

int RP(vector<int> u,int pos,int L=1,int R=n){
    if(Cnt(u)==R-L+1)return n+1;
    if(L==R)return L;
    int mid=L+R>>1;
    if(pos<=mid){
        int res=RP(lson(u),pos,L,mid);
        return res==n+1?RP(rson(u),pos,mid+1,R):res;
    }else{
        return RP(rson(u),pos,mid+1,R);
    }
}
int LP(vector<int> u,int pos,int L=1,int R=n){
    if(Cnt(u)==R-L+1)return 0;
    if(L==R)return L;
    int mid=L+R>>1;
    if(pos>mid){
        int res=LP(rson(u),pos,mid+1,R);
        return res==0?LP(lson(u),pos,L,mid):res;
    }else{
        return LP(lson(u),pos,L,mid);
    }
}

方法

  • 最近元素查詢模型——線段樹左右第一個查詢法,程式碼與上類似

D - k-Maximum Subsequence Sum

題面

長度為 $n$ 的數列,支援兩種操作:

  1. 修改某個位置的值。

  2. 詢問區間 $[l,r]$ 裡選出至多 $k$ 個不相交的子段和的最大值。

一共有 $m$ 個操作。

題解

要求 $k$ 個不交的,那麼可以先求出最大子段和,假設區間為 $[l, r]$,然後給區間 $[l, r]$ 內的所有元素取相反數,也就代表著此後你要是不想選這個數,那麼就取一遍相反數抵消掉,以此類推做 $k$ 輪。

線段樹需要維護:區間和,字首和最大值,字尾和最大值,區間和最大值,字首和最小值,字尾和最小值,區間和最小值,以及每種最大最小值取到的方案。

時間複雜度 $\mathcal O(n \log n)$。

方法

  • 線段樹結合貪心

程式碼

連結

E - Max Mex

題面

給定一棵有 $n$ 個點的樹,每個節點有點權。所有的點權構成了一個 $0\simn - 1$ 的排列。有 $q$ 次操作,每次操作 $1$ 為交換兩個點的點權,操作 $2$ 為查詢 $Mex(l)$ 值最大的 $Mex(l)$ 值,其中 $l$ 是樹上的一條路徑。定義一條路徑 $l$ 的 $Mex$ 值 $Mex(l)$ 為這條路徑上最小的沒有出現過的自然數

$2\le n\le 2\times 10^5,1\le q\le 2\times 10^5$

題解

考慮使用線段樹維護維護值域,也就是對於值域區間 $[l, r]$ 的點,他們在樹上的位置能否組成一條鏈,如果可以這個鏈的端點是誰。合併的時候分類討論。

查詢時記錄當前維護值域之前的資訊,進行合併

方法

  • 線段樹維護其他資訊

    線段樹不一定維護數值資訊,只要是有結合律的操作都可以,比如本題的合併

程式碼

連結

F - The Fair Nut's getting crazy

題面

給定序列 ${\alpha}$,求有多少個四元組 $(a,b,c,d)$ 滿足以下條件

  1. $a<c\le b<d$

  2. $\forall i\in[c,b],\forall j\in[a,d],\exist!i=j,\alpha_i=\alpha_j$

解法

令 $pre_i=\max\limits_{\alpha_j=\alpha_i,j<i}j,nxt_i=\max\limits_{\alpha_j=\alpha_i,j>i}j$

則對於一個合法四元組 $(a,b,c,d)$,有 $\max\limits_{i=c}^bpre_i<a<c\le b<d<\min\limits_{i=c}^bnxt_i,$

易得最遠情況下, $a=\max\limits_{i=c}bpre_i+1,d=\min\limits_{i=c}bnxt_i-1$

所以 $\max\limits_{i=c}^bpre_i+1<c\le b<\min\limits_{i=c}^bnxt_i-1$

這關乎兩個變數,所以假設我們列舉 $c$ 則答案 $b$ 的選取具有單調性

當 $b$ 去到最遠時,答案為 $\sum\limits_{i=c}b(c-\max\limits_{j=c}ipre_j-1)(\min\limits_{j=c}^inxt_j-1-i)$

由於計算的下邊界都是 $c$ 考慮倒序列舉,動態維護上式

展開得:$\sum\limits_{i=c}^b (c-1) * \min\limits_{j=l}^inxt_i - (c-1)*(i+1) - \max\limits_{j=c}^ipre_j * \min\limits_{j=c}^inxt_j + \max\limits_{j=c}^ipre_j * (i+1)$

用線段樹分別維護即可

抽象化方法

  • 先數學化,再推導

  • 多變數關聯情況——列舉+維護

    如上式中會出現一個同時與 $b,c$ 相關的式子,我們可以考慮列舉一個,維護一個

  • 維護法——拆式子

    將式子拆開,分別維護每一部分,要比維護整體更簡單

G - Useful Algorithm

題面

定義 $val(a,b)=\max\limits_{{i|a+b在二進位制的第i為下進位}}w_i$,例如 $\because 5+3=101_2+11_2=1000_2,所以val(5,3)=\max(w_1,w_2,w_3)$

給定長度為 $n$ 的序列 ${c}$ 和 ${d}$,求$\max\limits_{i,j}val(i,j)\times(d_i+d_j)$,並支援單點修改 $c,d$

$1\le m\le 16,1\le c_i\le 2^m,1\le n\le 10^5,1\le d\le 10^9$,強制線上

解法

$$
\begin{aligned}
&\max\limits_{a,b}\max\limits_{{i|a+b在二進位制的第 i 位進位}}w_i\times(d_a+d_b)
\=&\max\limits_{i}w_i\max\limits_{{a,b|a+b在二進位制的第 i 位進位}}d_a+d_b
\&令A=a\bmod 2i,B=b\bmod2i,f_A=\max_{i\bmod 2^i=A} d_i
\=&\max_iw_i\max_{A+B\ge 2^i}f_A+f_B
\&令g_A=f_{2^i-A}
\=&\max_iw_i\max_{A\le B}g_A+f_B
\end{aligned}
$$

對於每一位維護一棵線段樹即可

抽象化方法

  • $a+b\ \ \ \ p$ 進位制下第$i$ 位進位是指 $a\bmod p^i+b\bmod p^i\ge p^i$

  • 拆式子——交換內外迴圈

    本題中將外迴圈變為每一位,內迴圈變為數,以簡化處理

  • 形如 $a\cdot b\ge C的卷積$,可以化為 $C\cdot \overline{b}\le a$,用線段樹進行維護

    二元運算 $\cdot$ 可以為 $\oplus+\times$等存在逆元的運算

H - Vacation

題面

給定序列 $a_{1\sim n}$, $m$ 個操作,與一個限制 $c$ 。

單點修改,查詢區間中長度不超過 $c$ 的最大子段和。

$1\le c\le n\le 2\times 10^5,1\le m\le 5\times 105,-109\le a_i\le 10^9$

題解

參考題解:GYM103861F 解題報告

先將序列按照長度 $c$ 分塊。

最終答案僅可能來自於兩種情況

  • 屬於一個塊

  • 跨過至兩塊

對於第一種情況,我們直接維護一個普通的最大子段和。

對於第二種情況:答案一定由一個字尾加上一個字首組成。令 $l,r$ 表示左右端點在其各自段中的編號,易得 $l\ge r$ 。所以我們去維護 $\max pre_x,\max suf,\max_{x>y}suf_x+pre_x$ 就行了(其中 $pre$ 表示這一段的字首,$suf$ 表示前一段的字尾)。

所以說,我們需要維護三種線段樹

  • 維護最大欄位和

  • 對於每一塊,維護與前一塊 $pre,suf$ 拼接情況

  • 對於全域性,維護前兩種線段樹在考慮完整段時的答案

下面是具體操作:

修改

修改整棵最大子段和線段樹的答案並更新維護答案的線段樹

對前面塊的字尾和進行字首加並更新維護答案的線段樹

對後面塊的字首和進行字尾加並更新維護答案的線段樹

查詢

令 $L,R$ 表示左右端點 $k_l,k_r$ 為左右端點所在的塊, $l,r$ 分別為左右端點的塊內編號。

  • 當 $R-L+1\le c$ 直接詢問最大子段和

  • 當 $(R-L+1>c)\land(k_r=k_l+1)$,此時將一個塊分為了三個部分 $[1,l),[l,r],(r,c]$,答案來自於三種情況。

    • $\max_{l\le y<x\le c}suf_x+pre_y$

    • $\max_{x\in [1,l)}pre_x+\max_{x\in [l,c]}suf_x$

    • $\max_{x\in [1,r]}pre_x+\max_{x\in(r,c]}suf_x$

    取最大值即可。

  • 當 $(R-l+1>c)\land(k_r>k_l+1)$,答案來自於兩種情況

    • 中間部分,即 $k_l+1\sim k_r-1$ 中的整段最大子段和同 $k_l+1與k_l+2,\cdots,k_r-2與k_r-1$ 中的完整跨段關係。

    • 兩邊部分,轉化為兩個情況二。

時間複雜度 $\mathcal O((n+m)\log n)$

方法

  • 分段維護線段樹

  • 將兩端之間有關聯的資訊放入一個線段樹進行處理。

J - Game: Celeste

題面

數軸上有 $n$ 個點,第 $i$ 個點的座標為 $x_i$,權值為 $a_i$。小 A 可以從 $x$ 跳到 $[x+L,x+R]$ 的一個位置,跳到一個位置會拾取當前位置上權值,他想從第 $1$ 個點跳到第 $n$ 個點,並使得拾取權值的集合單調不增排列後的字典序最大。若不能到達,輸出 $-1$。

$\forall i\in[1,n-1],x_i<x_{i+1}<10^9,1\le a_i\le n\le 10^5,1\le L,R\le 10^9$

解法

用線段樹維護所選集合。考慮單調佇列最佳化 DP。

按照字典序每次選出最“大”的集合,轉移就是以此版本為基礎建立可持久化線段樹。

比較集合大小就用線段樹上二分,如果 $root[n]=0$,則不能到達。

抽象化方法

  • 維護集合——權值線段樹

  • 可持久化資料結構——一種轉移關係

    所以可以用來DP

  • 資料結構比大小,定義其大小關係,以便用在$\min,\max$ 等情境中。

K - 道路建設

題面

給定平面上 $n$ 個點的座標,求前 $k$ 小的點曼哈頓距離之和。

$2\le n\le 2.5\times 10^5,1\le k\le \min(2.5\times 10^5,\frac {n(n-1)}{2})$

題解

為了方便先離散化,把 $x, y$ 均離散化成不同的。

因為 $k$ 比較小,考慮對於每個點求出右側距離他最近的點,然後把這些距離扔到一個堆裡,每次取出最小值。最小值對應的點為 $u$。把距離 $u$ 第二近的點的距離和 $u$ 扔到堆裡。

因為我們限定了只考慮橫座標在一個點 $(x',y')$ 右邊的點 $(x,y)$。

  • 當 $y>y'$ 時,$|x-x'|+|y-y'|=(x+y)-(x'+y')$

  • 當 $y<y'$ 時,$|x-x'|+|y-y'|=(x-y)-(x'-y')$

所以查詢距離 $(x',y')$ 最近的點只需要查詢 $[1,y')$ 裡的 $x-y$ 的最小值和 $(y'n]$ 內 $x+y$ 的最小值

考慮從右到左掃描線,用主席樹維護區間 $y + x$ 的最小值和 $x − y$ 的最小值,每次加入一個點。

如果要找第二小值,就把第一小值對應的 $y$ 的地方設為正無窮即可。注意為了不影響其他點的線段樹,這裡也需要可持久化(即新建節點)。

方法

  • 離散化

    在離散化時去重就是相同對相同,在離散化的時候不去重並加上標記就是相同對不同,這樣離散為不同有助於許多情況的簡化。

  • 可持久化的修改

    新建節點——再次可持久化,以避免對後續版本造成影響。

  • 掃描線

    從一個方向至另一個方向的動態線段樹資訊就是掃描線,這樣確定了一個列舉(處理)順序,方便處理

L - 樹

題面

給定一棵 $n$ 個結點的有根樹 $T$,結點從 $1$ 開始編號,根結點為 $1$ 號結點,每個結點有一個正整數權值 $v_i$。

設 $x$ 號結點的子樹內(包含 $x$ 自身)的所有結點編號為 $c_1,c_2,\dots,c_k$,定義 $x$ 的價值為:

$
val(x)=(v_{c_1}+d(c_1,x)) \oplus (v_{c_2}+d(c_2,x)) \oplus \cdots \oplus (v_{c_k}+d(c_k, x))
$

其中 $d(x,y)$ 表示樹上 $x$ 號結點與 $y$ 號結點間唯一簡單路徑所包含的邊數,$d(x, x) = 0$。$\oplus$ 表示異或運算。

請你求出 $\sum\limits_{i=1}^n val(i)$ 的結果。

$1\le n,v_i\le 525010$

題解

將 $(v_{c_i}+d(c_i,x))$ 看作一個數,我們發現這實質上是要支援三種操作——合併子樹資訊、全域性加一與插入一個值,維護一種資訊——全域性異或和。由於是二進位制資訊,這裡考慮0/1字典樹,合併子樹資訊與插入一個值都很簡單。

考慮如何全域性加一。

我們發現對一個數加一在二進位制下的步驟可以解釋為,找到最低為的 $0$ 將其賦為 $1$ 並將那些位數比它低的 $1$ 複製為 $0$。

回到這顆0/1樹上,可以解釋為先交換一個節點兩條邊下面的兩棵子樹,再向交換後的 $0$ 邊進行遞迴操作,這樣一次複雜度為 $\mathcal O(\log v)$

考慮維護異或值,我們可以考慮每條邊的貢獻。如果一條 $1$ 邊的子樹中有奇數個值時,累計這個一,否則不累計,每次維護 $\mathcal O(1)$。

時間複雜度 $\mathcal O(n\log v)$

方法

  • 01-trie 可以用來維護一些數字的異或,支援修改

    其插入、刪除、全域性加一、全域性減一(從遞迴 $0$ 邊變為遞迴 $1$ 邊)、合併操作都十分常見。注意

M - 眾數

題面

定義眾數為序列中出現次數嚴格大於一半的數字。

一開始給定 $n$ 個正整數序列,編號為 $1 \sim n$,初始序列可以為空。

有 $q$ 次操作,操作有以下型別:

  • $1 \ x \ y$:在 $x$ 號序列末尾插入數字 $y$。
  • $2 \ x$:刪除 $x$ 號序列末尾的數字。
  • $3 \ m \ x_1 \ x_2 \ x_m$:求 $x_1, x_2, \ldots, x_m$ 合併後的眾數。不存在返回 $-1$。詢問中的合併操作不會對後續操作產生影響。
  • $4 \ x_1 \ x_2 \ x_3$:新建一個編號為 $x_3$ 的序列,其為 $x_1$ 號序列後順次新增 $x_2$ 號序列中數字得到的結果,然後刪除 $x_1, x_2$ 對應的序列。

$q,n\le 5\times 10^5,\sum m\le 5\times 10^5$

題解

方法

  • 主席樹+連結串列

N - 樓房重建

單側遞迴線段樹

題面

維護一個序列,線上單點修改,求出每一時刻各段的字首最大值數目。

$1\le n,m\le 10^5$

題解

既然是線段樹,首先考慮如何合併資訊。

如圖,黑線兩側是一個節點的左右子樹,很明顯左子樹的答案我們是一定要保留的,對於右子樹,我們應該保留那些比黃色的線更高的節點,如果直接用可持久化平衡樹維護每個子樹中的所有點,一次去 $\mathcal O(\log)$的查詢自然是可以的,但這樣太麻煩。

我們知道,在有序的序列上二分查詢比一個數小的複雜度是 $\mathcal O(\log)$ 的,我們可以用同樣的原理,圖中紅線是將右兒子再次分割,我們可以發現,要麼一個孫子全部在黃線上,要麼另一個孫子全部在黃線下,我們都只需要遞迴查詢另一個。

這個問題也就是一次上傳是 $\mathcal O(\log)$ 的,這樣總複雜度 $\mathcal O(n\log^2n)$

方法

  • 線段樹維護單調序列

    也就是本題的一個套路

  • 線段樹的 Up 可以看作一個從來是線段樹的重中之重,在分析時,我們可以將其看作一個新的問題,這個問題又可以有多種解法,比如說這題,查詢黃線上的數,就可以線上段樹上再次遞迴實現,不僅如此,我們可以將其他資料結構、演算法等知識運用其上,解決問題。

  • 本題也可以使用 T 題的方法達到 $\mathcal O(n\log n)$

P - Rikka with Data Structures

題面

給定序列 $a_{1\sim n}$

有 $m$ 次三種型別的操作:

  • 區間加
  • 區間賦值
  • 給定$l\ r\ x$:計算滿足 $\max\limits_{i=\min(x,y)}^{\max(x,y)}a_i=max{A_x,A_y}$ 的 $y$ 的數量。

$多測,1\le T\le 200,1\le n,m\le 10^5,\sum n,\sum m\le 10^6$

題解

可以注意到 $y$ 的位置是由若干比 x 小的位置,及第一個比它大的位置後面的字首和最大值構成的,那個位置可以用“最近元素查詢模型”找,後面那一段用單側遞迴線段樹處理。

複雜度小常數 $\mathcal O(n\log^2n)$,最近元素查詢模型換成 $\log^2$ 的二分加線段樹會超時。

方法

  • 最近元素查詢模型

  • 單側遞迴線段樹

S - Bear and Bad Powers of 42

題面

定義一個正整數是壞的,當且僅當它是 $42$ 的次冪,否則它是好的。

給定一個長度為 $n$ 的序列 $a_i$,保證初始時所有數都是好的。

有 $q$ 次操作,每次操作有三種可能:

  • 1 i 查詢 $a_i$。
  • 2 l r x 將 $a_{l\dots r}$ 賦值為一個好的數 $x$。
  • 3 l r x 將 $a_{l \dots r}$ 都加上 $x$,重複這一過程直到所有數都變好。

$n,q \le 10^5$,$a_i,x \le 10^9$。

題解

T - 前進四

題面

單點修改,詢問 $a_x​,⋯,a_n​$ 的不同的字尾最小值個數。

$1\le n\le 10^6$

題解

很明顯有一個$\mathcal O(n\log^2n)$ 的單側遞迴線段樹做法。但這道題會超時。

如果我們把時間當作空間的一維,那麼一個序列上的操作其實是在二維平面上的操作,如圖:

未命名課件 20240704-0917 第1頁.png

我們在時間軸上進行掃描線,單點修改,維護字首資訊。

而這道題,我們發現查詢是一個單點修改,維護字尾資訊,然而修改卻只在一個時間段有效,所以對於這道題,可以考慮將其轉過來。

未命名課件 20240704-0917 第2頁.png

變成一個區間賦最小值,字尾序列掃描線。

方法

  • 考慮時間維度

相關文章