1. 程式人生 > >圓方樹和廣義圓方樹學習小記

圓方樹和廣義圓方樹學習小記

圓方樹,解決毒瘤仙人掌問題的利器。

有了圓方樹,什麼樹上的演算法都可以套在仙人掌上了,比如說點分治、樹鏈剖分、虛樹等等。

OI資料結構無窮無盡,只有你不會的,沒有你想不到的。

資料參見WC2017講稿。

圓方樹:

圓方樹分為圓點和方點。

圓點就是原來有的點,方點是新加的點。

對於每一個點雙聯通分量,這個分量裡面的邊要刪掉,分量裡的所有點往分量對應的方點連邊,分量出去的邊照連。

可以證明這樣還是一棵樹,然後就可以根據題意亂搞了。

廣義圓方樹:

把圓方樹建到無向圖去。

其實是一樣的,依然是對每一個點雙聯通分量搞搞。

tarjan要寫得好。

裸題:
「SDOI2018」戰略遊戲

廣義圓方樹+虛樹

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define mem(a) memset(a, 0, sizeof a)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;

const int
N = 4e5 + 5; int T, n, m, Q, x, y, td; int dfn[N], low[N], d[N], z[N], tt, z0; struct edge { int final[N], to[N], next[N], tot; void link(int x, int y) { next[++ tot] = final[x], to[tot] = y, final[x] = tot; next[++ tot] = final[y], to[tot] = x, final[y] = tot; } void cl() { mem(final); mem(next
); tot = 1; } } e, e2; void tar(int x, int la) { dfn[x] = low[x] = ++ tt; z[++ z[0]] = x; for(int i = e.final[x]; i; i = e.next[i]) { int y = e.to[i]; if(!dfn[y]) { tar(y, i); low[x] = min(low[x], low[y]); if(low[y] >= dfn[x]) { td ++; while(z[z[0]] != y) e2.link(z[z[0] --], td); e2.link(z[z[0] --], td); e2.link(x, td); } } else if(i != (la ^ 1)) low[x] = min(low[x], dfn[y]); } } int bz[N], fa[18][N], dep[N], s[N], p[N], q[N], tp; void dfs(int x) { bz[x] = 1; s[x] += (x <= n); p[x] = ++ tp; for(int i = e2.final[x]; i; i = e2.next[i]) { int y = e2.to[i]; if(bz[y]) continue; fa[0][y] = x; dep[y] = dep[x] + 1; s[y] = s[x]; dfs(y); } q[x] = tp; bz[x] = 0; } int lca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); fd(i, 17, 0) if(dep[fa[i][x]] >= dep[y]) x = fa[i][x]; if(x == y) return x; fd(i, 17, 0) if(fa[i][x] != fa[i][y]) x = fa[i][x], y = fa[i][y]; return fa[0][x]; } int cmp(int x, int y) { return p[x] < p[y]; } int ff[N]; int main() { freopen("game.in", "r", stdin); freopen("game.out", "w", stdout); for(scanf("%d", &T); T; T --) { e.cl(); e2.cl(); scanf("%d %d", &n, &m); fo(i, 1, m) { scanf("%d %d", &x, &y); e.link(x, y); } mem(dfn); td = n; tt = 0; tar(1, 0); dep[1] = 1; s[1] = 0; tp = 0; mem(bz); dfs(1); fo(i, 1, 17) fo(j, 1, td) fa[i][j] = fa[i - 1][fa[i - 1][j]]; for(scanf("%d", &Q); Q; Q --) { int k; scanf("%d", &k); fo(i, 1, k) scanf("%d", &d[i]), bz[d[i]] = Q; sort(d + 1, d + k + 1, cmp); int d0 = k; fo(i, 2, k) d[++ d0] = lca(d[i - 1], d[i]); sort(d + 1, d + d0 + 1, cmp); k = 0; fo(i, 1, d0) if(i == 1 || d[i] != d[i - 1]) d[++ k] = d[i]; z0 = 0; fo(i, 1, k) { int x = d[i]; if(x == 1) {z[++ z0] = 1; continue;} while(z0 && (p[x] < p[z[z0]] || p[x] > q[z[z0]])) ff[z[z0]] = z[z0 - 1], z0 --; z[++ z0] = x; } while(z0) ff[z[z0]] = z[z0 - 1], z0 --; int ans = 0; fo(i, 1, k) { int x = d[i]; if(i == 1) {ans += (bz[x] != Q && x <= n); continue;} ans += s[x] - s[ff[x]] - (bz[x] == Q && x <= n); } printf("%d\n", ans); } } }

相關推薦

點雙聯通分量,廣義

點雙聯通分量 邊雙聯通分量想必看這篇部落格的同學就會,並且邊雙聯通分量理解和打起來比較簡單,就不再贅述了。 點雙聯通分量,類比邊雙的定義,它是原圖的極大無向子圖,滿足刪去子圖中任意一個節點以及與其相鄰的邊,其餘節點仍然連通。 如下圖,左中兩個均為一個點雙聯通分量,但最右邊圖中

廣義學習小記

圓方樹,解決毒瘤仙人掌問題的利器。 有了圓方樹,什麼樹上的演算法都可以套在仙人掌上了,比如說點分治、樹鏈剖分、虛樹等等。 OI資料結構無窮無盡,只有你不會的,沒有你想不到的。 資料參見WC2017講稿。 圓方樹: 圓方樹分為圓點和方點。 圓點就是

二叉廣義表的轉換

def har out char emp typedef con 逗號 字符串 1 //廣義表轉二叉樹: 2 設置一個標記變量k,初始值為-1; 3 設置一個標記結點p; 4 循環遍歷廣義表的字符串str; 5 如果str[i]是左括號:

資料結構作業10—陣列廣義表以及的基本概念(選擇題)

2-1已知廣義表L=((x,y,z),a,(u,t,w)),從L表中取出原子項t的運算是()。 (2分) A.head(tail(head(tail(tail(L))))) B.head(tail(head(tail(L)))) C.tail(head(head

二叉排序平衡二叉的關系

fill 樹的高度 == eight font 關系 avl樹 avi 等於   二叉排序樹: 二叉排序樹又稱二叉查找樹,亦稱二叉搜索樹。 二叉排序樹或者是一顆空樹,或者是具有下列性質的二叉樹: (1)若左子樹不空,則左子樹上所有結點的值均小於它的根節點的值; (2)若右子

LeetCode——中級演算法——圖——二叉的鋸齒形層序遍歷(JavaScript)

給定一個二叉樹,返回其節點值的鋸齒形層次遍歷。(即先從左往右,再從右往左進行下一層遍歷,以此類推,層與層之間交替進行)。 例如: 給定二叉樹 [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回鋸

二叉完全二叉一些規律

1、二叉樹具有以下規律:       1)二叉樹高度為i所在的層至多有 個節點       2)高度為k的二叉樹至多有 -1個節點       3)對於任何一棵二叉樹,若度為2的

AVL平衡二叉 平衡因子 右旋轉LL 左旋轉RR LR RL

  前言   今天要介紹幾種高階資料結構AVL樹,介紹之前AVL,會先說明平衡二叉樹,並將樹的學習路線進行總結,並介紹維持平衡的方法:右旋轉、左旋轉。   一、樹學習路線   1、路線總結   總結了一下樹的學習路線,如下圖:      2、說明   上面這個圖要從上往下進行一步一步學習;首先,

赫夫曼赫夫曼編碼

赫夫曼樹,又稱最優樹,是一類帶權路徑長度最短樹。 從樹中一個節點到另一個節點之間的分支構成這兩個節點之間的路徑,路徑上的分支數目稱為路徑長度。樹的路徑長度指的是從樹根到樹中其他每個節點的路徑長度之和。節點的帶權路徑長度是指從樹的根節點到該節點之間的路徑長度與該節點上所帶權值

B二叉排序(如紅黑)、BB+的區別

B樹是為了提高磁碟或外部儲存裝置查詢效率而產生的一種多路平衡查詢樹。 B+樹為B樹的變形結構,用於大多數資料庫或檔案系統的儲存而設計。 B樹相對於紅黑樹的區別 在大規模資料儲存的時候,紅黑樹往往出現由於樹的深度過大而造成磁碟IO讀寫過於頻繁,進而導致效率低下的情況

二叉:搜尋二叉完全二叉

搜尋二叉樹又叫作二叉樹查詢樹或者二叉排序樹, 所謂搜尋二叉樹是指對於任何一個結點,它的左子樹的所有結點都比這個根結點要小,它的右子樹的所有結點都比這個根結點要大。注意是根結點與左右子樹上所有的結點進行比較而不是僅僅與左右孩子結點進行比較,因此根據這個定義,那麼當按照中序

完美二叉, 完全二叉完滿二叉

樹在資料結構中佔有非常重要的地位。本文從樹的基本概念入手,給出完美(Perfect)二叉樹,完全(Complete)二叉樹和完滿(Full)二叉樹的區別。如果學習過二叉樹,但是對這三種二叉樹並沒有深入的理解,或者完全被國產資料結構教科書所誤導(只聽說過滿二叉樹和完全二叉樹)的朋友不妨花點時間耐著性子將本文仔細

完全二叉滿二叉的區別+完全二叉求節點問題

今天覆習了下二叉樹的相關知識,發現很多都忘掉了,所以在此記錄下 滿二叉樹 如圖,顧名思義,滿二叉樹說白了其實就是除了最後一層,所有節點都有兩個孩子, 所以: 假設現在有一棵深度為N的滿二叉樹: 總結點數就是2^N-1(計算公式:

Javascript之資料結構與演算法的二叉二叉搜尋實現

Javascript之資料結構與演算法的二叉樹和二叉搜尋樹實現 簡介 程式碼實現 簡介 二叉樹中的節點最多隻能有兩個子節點:一個是左側子節點,另一個是右側子節點。 二叉搜尋樹( BST)是二叉樹的一種,但是它只允許你在

資料結構-二叉二叉查詢

先按樹-二叉樹-二叉查詢樹的順序解釋會比較清楚。 一,樹 樹(Tree)是n(n≥0)個結點的有限集。在任意一棵非空樹中: (1)有且僅有一個特定的被稱為根(Root)的結點; (2)當n>1時,其餘結點可分為m(m>0)個互不相交的有限集T1,T2,…,Tm,

資料結構----完全二叉滿二叉以及前序、中序、後序遍歷

一) 滿二叉樹和完全二叉樹 1.滿二叉樹定義: 又叫Full Binary Tree. 除最後一層無任何子節點外,每一層上的所有結點都有兩個子結點(最後一層上的無子結點的結點為葉子結點)。也可以這樣理解,除葉子結點外的所有結點均有兩個子結點。節點數達到最大值

《資料結構與演算法C#語言描述》筆記12_二叉二叉查詢

樹的定義 樹,由邊連線的一些列節點。樹是一種非線性的資料結構。 根節點,樹上最高的節點。 父節點,某個節點的上層節點。 子節點,某個節點的下層節點。 葉子,沒有任何子節點。 二叉樹 二叉樹,子節點的數量不超過兩個的樹。 父節點的兩個節點分別稱為左節點和有節點。 二叉查詢樹

紅黑平衡二叉 區別

紅黑樹和平衡二叉樹(AVL樹)類似,都是在進行插入和刪除操作時通過特定操作保持二叉查詢樹的平衡,從而獲得較高的查詢效能。自從紅黑樹出來後,AVL樹就被放到了博物館裡,據說是紅黑樹有更好的效率,更高的統

完全二叉滿二叉的區別

堆的話一般都是用完全二叉樹來實現的,比如大堆和小堆。一個樹節點的度數就是這個樹節點有多少子節點,和樹的深度意義不同。 依據二叉樹的性質,完全二叉樹和滿二叉樹採用順序儲存比較合適 完全二叉樹是效率很高的資料結構,堆是一種完全二叉樹或者近似完全二叉樹,所以效率極高,像

判斷完全二叉滿二叉

(一)判斷完全二叉樹 特點一: 只允許最後一層有空缺結點且空缺在右邊,即葉子結點只能在層次最大的兩層上出現;  特點二: 對任一結點,如果其右子樹的深度為j,則其左子樹的深度必為j或j+1 即度為1的點只有1個或0個  解題思路: 首先一棵空樹是完全二叉樹 利用佇