BZOJ 2200再ルート道路およびWWを話します。
FJは調査する彼の牛乳販売プログラムのための新たな販売エリアです。彼は、牛乳の町T(1≤T≤25000)を望んでいたT.番号1〜R(1≤R≤50000)による論文及びPルート(1≤P≤50000)接続の間の都市の道路。I私は愛のBiに町を結ぶ各道路や経路は、CIとして過ごしました。道路のために、0≤CI≤10000;しかし驚くべきであるルートを過ごす、(-10000≤CI≤10000)Ciは負であってもよい過ごしました。道は、すべてのCIを過ごし、愛からのBiに、また双方向からの愛に、双方向です。ただし、航空会社のコントラスト、唯一の愛からのBiへ。:実際には、近年のテロリスト傲慢に、社会の調和のために、私たちは、ことを確認するために、ポリシーの数を導入バイへの愛からのルートがある場合は、保証は道路やルートの数によって愛バイから復帰することはできません。牛のFJの世界が力に〸ポイントを認識しているため(監督エッジは、任意の環に存在しない無向エッジを加重されている)、彼はすべての町に牛を輸送する必要があります。彼は最も安価な計画のすべての町に牛を送ったり、これが不可能であることを知っているSから町の中心を探していました。(ポイントへの単一始点最短経路からSデマンド)、O(nlogn)
にアップデート:大ドットとして、通信ブロックが複数形成されている全てのエッジにリストに追加され、その後、DAGが形成されている側には添加しない、通信ブロック場合は、実行dijkstar直接通信ブロック0ではありませんDISベースWW、DP順序はトポロジー的側面、DIS更新、行う内部通信ブロックdijkstarを使用して持っています。
通信ブロックを実行する方法Dijkstar:DISが更新DISは正の無限遠点スタックを投げていない、更新した後、Dijkstarを実行された複数のポイントを。
POJ 1125株式仲買人グレープバイン
それらの間の一方向通信パスの数が存在し、N個の株式仲買人は、お互いにメッセージを渡すことができるあります。今みんなに始まった誰かによって配信されるメッセージがあり、誰もがメッセージを受信するように、最短時間での順序で配信されるべき人お願いします。
フロイド各単一のヒトソースの最短経路を計算し、最小値を取って、グローバル最短ランを計算し、その人はWW情報を伝えるために使用されるべきです。
POJ 1502 MPI大渦
これは、プロセッサに要する時間は、最大の必要な最初のプロセッサ時間からすべての他のプロセッサに送信された情報を要求し、Nは、下三角行列との間で情報を送信する与えます。(原題要求は最小です)
下三角行列を与え、あなたは2つのプロセッサ間いつでも知ることができ、それが明確であるという問題が最短の単一のソース。
最長のシングルソースパスを取得する方法:単一ソースの最短経路は、変更の数よりも多い数よりも少ないです。
POJ 1511枚の招待カード
MのN点は、時点1からI点及び必要最小限に戻り、すべてのI、点1を求め図にエッジを有します。
WW:フォワード+シングルソースの最短経路図を構築
図建設+単一始点最短逆
付加し、
POJ 1724 ROADS
N及びM一方向都市道路と、各道路の長さと2つの電荷特性を有します。総コストを求めているの前提の下で都市Nに都市1からK最短を超えていません
通常のダイクストラを書く、メンテナンスが徒歩kが継続するよりもはるかにである以上かかります。
より多くのポイントに、建設されたN * kのポイントを開きます。次いで、各点レコードの二つの条件、すなわちとき番号のコストとこの点に到達します。
そうエッジ<U、V>、それは通常の実行ダイクストラ次に、エッジにuが連結されたVコストがCであり、我々は、対応する費用のそれぞれから取ることができ、Wの重量を想定するための√
POJ 1797ヘビー交通
図エッジにNによって与えられる点Mは、各エッジは、最大負荷を有します。
N(最大右側を求めて、すなわち、最小のパス)で点から点への最大重量を求めます。
分割:バイナリ答え、もし1 =>、ダイアグラムに追加される最大負荷> =中間、それから缶のみ再限界> =中間縁、と仮定nは、例示のために回答が増加可能です。
Dij:\(IF(DIS [V] <分(DIS [U]、W _ {(U、V)}))DIS [V] =分(DIS [U]、W _ {(U、V)})。 \)
Kruscal:最大スパニングツリー(右側降順w)を実行します
POJ 1062高価な持参金
(顔の問題が長すぎる、会場http://poj.org/problem?id=1062)
総費用:1つの価格+価格WW。
代替の側面である、低価格交換から首長国連邦物品の長さは、有望な経路であります
限界の状態にかかわらず:
私たちは、側面の間に構築されたオファー:<U、V、W>は、U =を表し>の辺の長さを持っているwはV、それは私が、その後商品を購入価格はワットですuがアイテムをV得ることを意味し、離れて出発の特定のポイントから一つの解決策は、1に最短必要です。
裏面考慮組み込み、最短別の1点を実行します。
制限された定格の場合を考えてみましょう:
私たちは、いくつかの間隔を列挙いると考えることができ、間隔の長さはMであり、
しかし、のためにがんYCH列挙Mが爆破かもしれないので、もし、我々は考慮にのみ100 Nをとり、Nの列挙は良い選択である、レベルの多くを与えることがあり、1つの必要性だけM +このセクションの状態に千万人を数えます√
列挙グレードのレンジ位置は、ポイントが範囲内にないレベルの位置、列挙O(N)を介してではありません
BZOJ 3040 *最短
Nポイントは、エッジの点Nに最も短絡点1(保証が存在する)Mため、有向グラフ。
1000000≤1≤N、1≤ M≤10000000
lydrainbowcatによって
二つの部分に分割されたエッジの組:
ランダムに生成
入力与えられました
スタックを最適化するための効率的なダイクストラアルゴリズム。
フィボナッチヒープ
ペアリングヒープ
https://paste.ubuntu.com/p/Mp2fXMKv8J/
実際には、(バルク側を占める)ランダムに生成された側を無視することは適切なソリューションを得ることができます。
https://paste.ubuntu.com/p/NHvZXTGnZp/
最小スパニングツリー
プリム
プリムは、生と死ではありません
全ての点は、2つのセットに分割され、S設定された通信ポイントを有し、点のセットを通信し、Tれていません
、T Uおよび集合Sの各セットの距離を計算します
\(d_u =分_ {<U、V>∈E、v∈S} \ {W_ {U、V} \} \)
コレクションSに選択されたエッジに対応する、集合T Sの最も近い点Uから選択
全ての点が集合Sに追加されるまで、上記処理が繰り返されます
ナイーブ劣る書き込み時間の複雑さ、スタック最適化するために使用することができる\(O((N + M )logN個の)\)
プリムは貪欲アルゴリズムであり、かつ誘導正しさを使用して証明するために必要な場合があります。
まず最初に選択されたエッジe1が特定の最適解スキームを含んでいなければならないことを証明
最適解は、エッジE1が含まれていない場合は、e1が表示されますリングに加え、リングe1の側よりも大きい存在している、E1は良い答えで置き換えます
最適解は、最初のk個の選択された側を含むと仮定し、E1、E2、...、エク、同様EK + 1は最適解に存在することを証明されています
誘導、Nプリムアルゴリズムを使用して、 - 側は最適解を形成します
Kruscal
辺の重みに応じて昇順に全ての側
順次各エッジ検討(<u_i、V_I> \)\し、そして選択されたエッジの前に、このエッジは、環を形成する場合、このエッジが選択されていない、そうでない場合、このエッジを選択
以上のすべてのエッジを考慮した後、選択された側のマストは、最小スパニングツリーを構成します
チェックして、サポートを設定する必要があり、時間の複雑さは、一般的にOであると考えられている(MlogM)
証明.JPG放棄
マトロイド最適化問題:コレクションは、各要素に重みを与え、最小重量(大)最大独立集合を見つけます。
マトロイドは、貪欲アルゴリズムを最適化:
最初は空、独立したGの現在のセットを維持します。G∪{X}は独立して設定されている場合、要素の値は、それが重量X X独立に設定し、疲れ追加回答を参加する、列挙要素xを昇順、その重みに従ってソートされます。最終結果は、重量と最小限の最大の独立したセットです。
POJ 1258アグリネット
N村があり、全体の村の間に形成されています。隣接行列所与今N通信村のエッジの最小の可能な全体的な長さを選択します。
それは木の聖歌のW最小全域を実行することです。
道路を構築POJ 2421
今すべての村通信の最小全長所望N村、いくつかの既存の道路が存在します。
既存の道路の長さは0に設定し、最小スパニングツリーを実行します。
POJH 2560のそばかす
平面内にN個の点を所定の最小距離、すべてのポイントを見つけて、連
\(O(N ^ 2) \) 内蔵エッジ、二点の距離全ての偶数側の要件、および、最小スパニングツリーを実行している間。
POJ 1789トラックの歴史
N番号がありますが、それぞれの番号が7桁の数字でした。二つの数値間の距離は、2つの数の他の数を考慮して生成された数の異なるビット数のために定義されています。私は1個の数からすべての数字を生成する最小のトータルコストで始めたいです。
\(O(N ^ 2) \) 建物の側面、及び最小全域木。
BZOJ 1601灌漑
ファーマージョンは彼のN(300≤1≤N)ファーム1からnまでの農地タグ番号に注ぐことを決定しました。灌漑のための土地の一部は、他の農場や貯水池を建設する土地からの流用の2つの方法があります。ビルドリザーバは、(1≤のWi 100000≤)のWiをとり 、 2ランド取りに接続\(P_ {I、J} \)(1≤ \(P_ {I、J} \) 100000≤、$ P_ {I 、J} = P_ {J、 I}、P_ {I、I} = 0 $)。 ファーマージョン計算された最小必須価格。
、スーパーリザーバ点を確立する通信辺の長さと超のWiリザーバを選択すると考え時点でリザーバを確立する、水が選択された長さのPI、J、及びI jの尖った端に接続されています。目標は、リザーバとスーパーポイントとのすべての通信するように、エッジの長さ及び可能な限り小さくを選択することです。
これは、最小スパニングツリー聖歌を実行することですか?
スキーとBZOJ 2753のタイムカプセル
雪山スキーに、ここで、レールとスライドトラックNの間(また、目的の)M用交差点の分布、それぞれが関心と高さのHi iの数を有しています。関心jのスライドから関心のI場合にのみiとj、i及びj以上の高さとの間のエッジの存在。グライドは、多くの観光スポットを訪問する最短ルートを使用するようにしたいです。パスだけで観光スポットを訪れる場合は、彼があまりにも少ないと感じます。だから、彼の持ち込みのアウトタイムカプセル。これは、すぐに(移動は、摺動距離とはみなされませんなし)の観光スポット経由最後に戻ることができます食べた後、非常に魔法の薬です。今までに(そのような通過の観光スポットや観光スポットへの最後のパスのような)長いアトラクションに戻ることができるようになる前に、この特効薬が連続的に消費されることに注意してください。さて、第1スポットには、感情的に、ターゲットの足元を見て立っていました。彼は(すなわちアトラクションの最大数が最小の総距離を滑空することの前提の下を通して会う)、口座にタイムカプセルの消費量を取ることなくケースにプログラムの多くの観光スポットとして最短距離グライドスライドを〸ポイントを知りたいと思いました。あなたは彼が最短距離や観光スポット、それの数を見つけることができますか?
到達可能な観光を簡単にDFSやBFSによって決定します。
我々は残りのすべての点がWWに達することができることを保証するために、削除のポイントに到達しません。
すべてのエッジが鳴るしてはならない、または我々はタイムカプセルWWを使用することができます。
木を形成すべき最適解は、必要な時間は、全ての辺の長さの合計です。ツリーアルゴリズムをまたがるクラスカル最小を使用してこの問題を解決すると考えるのは簡単。
キーワードの最初のポイントの高さ、2番目のキーワード辺の長さに到達します。ときに、同じ優先度の高い短辺の長さが、点の高優先度の高い側に到達します。降順最初のキーワード、小から大への第2のキー。
BZOJ 2561最小スパニングツリー*
、Nポイントを順次3つの正の整数U与え、1からNまで番号が付けられてい| V | |、M = | E図正にG = <V、E>、N =の右側に無通信側を与え、V、L(u、v)は、今エッジを追加するLエッジ(u、v)は、次いで、このエッジは、最小スパニングツリーの両方に表示されることが作ることができるようにエッジの最小数を削除する必要があると仮定するとそれはまた、最大スパニングツリーに発生する可能性がありますか?
事前スキル:ネットワークフロー最小カット
公式GUGU、最も致命的。
木を倍増
根付いツリー(任意に設定ルート)
最近の共通の祖先
チェーン情報(及び、最も値)
優秀な時間複雑
シーケンスを倍増
通常のシーケンスメモリは、たとえば、STテーブルに思いを倍増しました。
\(F_ {I、J} \) 記録間隔\([I、I + 2 ^ J - 1] \) 情報(または間隔部と最も値)
\(F_ {I、J} =マージ(F_ {I、J-1}、F_ {I + 2 ^ J-1、J-1})\)
答えがいくつか使用する区間[L、R]取り外す\(F_ {I、Jを} \) への
必要な間隔の最良値場合、F_ {L $、K}取ら\(および\) $缶F_ {2-R&LT ^ K、K}を、前記
\(K =⌊loG_2(R - L + 1)⌋\)
要求間隔と取ることができる場合、\(F_ {L、K1} 、F_ {+ 2 ^ {K1 L}、K2}、F_ {1 + 2 ^ {K1} + 2 ^ {K2}、K3}、\) ...することができます
木を倍増
各鎖のルートノードへのツリーの点からも同様の形状を有しています。
\(F_ {I、Jは} \) iは$ 2 $ ^ステップ接合部Jを移動する点を表します
\(F_ {I、0} \) 点iの親ノードであります
$ F_ {I、J} = F_ {F_ {I、J-1}、J-1} $
ステップを上に移動U kを解決するためにどのように何点にありますか?
Kは、例えば、2及び書き込みのパワーが続く\(2 ^ 11 = 3 + 2 + 2 ^ 0 ^ 1 \) 。
で\(G_ {I、J} \) iが上方ステップjを移動した結果を表します。
\(G_ {U、F = 11} _ {_ {区、10}、0} \)
\(G_ {U、F = 10} _ {_ {区、8}、1} \)
\(G_ {U、8} = F_ {U、3} \)
O(logN個)のステップで完了しました。
最も一般的な木の乗数は2点の共通の祖先を解決するのに便利です。
そして、Bの共通の祖先を解決します:
AおよびBは同じ高さに調整されています
一致点が答えたときの分析a、bは、一致しています
ましょうとBは、2つのモバイルに重ならないように、可能距離と共に上方へ移動します
このとき、二つのノードの父親が答えです
シングル問い合わせ時間計算量O(logN個)
対処方法([I] [J F \ ] \を)
処理DFS:明らかに記録された父の\(F [I] [0] FA = \) 、各点に対して実行forループ。
for(int j=1;j<=20;j++)
f[i][j]=f[f[i][j-1]][j-1];//大概没写错ww
LCAを解決するための一般的な方法は以下のとおりです。
木を倍増
ツリーチェーン分割
DFS順+ RMQ
DFSシーケンス+ RMQ:
我々は最初の二つの点について次に、我々は再び、アレイに追加する、ポイントを介してバックトラックならば、アレイに添加される点を通過すると、DFSの長さ2nのアレイを画定しますLCA xに対して、アレイ内の二つの中間点に一度だけ、X、及び最小深さです。したがって、この方法では、我々は、各間隔ANS与えることを、あらかじめテーブルST(O(nlogn))を使用することができます。
上向きのパス
最も値のVトップ右にUからのパスを解決する方法は?U vは祖先であることを確認してください。
\(M_ {I、Jは} \) iが上方に移動始点を表す\(2 ^ j個の\)最もエッジ重み値をステップ
\(M_ {I、0} = W_ {I、F ather_i} \)
\(M_ {I、J} =マージ(M_ {I、J-1}、M_ {F_ {I、J-1}、J-1})\)
木は最新の回答の値を倍に上がる時にモバイルセクションを取ります
ツリーパス
注Gが= LCA(U、V)は、UからVへのツリー経路は、2つのセクションに分割することができます。
gのUからパス
GパスVからの
UからVへのパスの右側を解決する方法と?
上向きの経路が再結合答えを解決するために、それぞれ、2つの経路に分割します。
ツリーチェーン分割
チェーンツリー:パスが回りません
スプリット:一方の鎖に属するすべてのポイント
これは、優れた特性を有しています。
ヘビー息子:最大サブサブツリーノードのサイズ
重鎖:ダウンするこのような観点から、再選択されている彼の息子は、葉を行きます
ライト側:重鎖のいずれかの側
Uは、任意の点からのルートに行き、重鎖の数を介して、光ミドルエッジ数はどのくらいですか?
重鎖、軽側、サブツリーの少なくとも2倍のサイズを取る、O(logN個)を知ることは容易です。
各光側ホップ、サブツリーのサイズが倍元に増加され、それはlogN個ストリップ光側の唯一の最大値です。
いくつかのマーク
\(dep_u \)は、点Uの深さを示します
\(fat_u \)は、ノード点Uの父を表します
\(top_u \)トップノードuの重鎖点を表します
\(dfn_u \) DFSポイントUの重い息子の下にタイムスタンプの優先度を表し、
\(end_u \)重優先息子DFSの下で最大のタイムスタンプUサブツリーの点を示します
\は(size_u \)ノードにルートとするサブツリー内の数Uを表します
\(son_u \) U-重息子が表す
息子の重量を決定するために、二回:. 1統計サブツリーのサイズをDFS
2.断面重鎖
void dfs1(int u,int fa){
dep[u]=dep[fa]+1;
fat[u]=fa;
size[u]=1;
int v,num=0;
for(int i=head[u];i;i=edge[i].nxt){
v=edge[i].to;
if(v!=fa) dfs1(v,u);
size[u]+=size[v];
if(size[v]>num) son[u]=v,num=size[v];
}
}
void dfs2(int u,int fa){
dfn[u]=++cnt;
if(u==son[fa]) top[u]=top[f];
else top[u]=u;
if(son[u]) dfs2(son[u],u);
int v;
for(int i=head[u];i;i=edge[i].nxt){
v=edge[i].to;
if(v!=fa&&v!=son[u]) dfs2(v,u);
}
end[u]=cnt;
}
LCAを求めているチェーンスプリットツリー:
最近の共通の祖先の点AとBを探しています。
Keeさん\(TA = top_a、TB = top_b \)
- taは結核=場合、同じ重鎖中のAとBは、より小さな深さであり、LCA
- ターイフ!= Tbの:
- 場合\(dep_} {TA> TB dep_ {} \) 、次いでせ\(= at_ F {TA } \)
- 場合\(dep_} {TA <TB dep_ {} \) 、次いでat_ {TB} F = $ bを聞かせて $
树的结构较为复杂,相较而言我们更喜欢序列这样的一维结构,因为有丰富的数据结构及其它算法可以处理序列上的种种问题。那么能否将树转化为序列以便维护信息?如果按照 \(d f n_u\) 将树转化为序列,有哪些有用的性质?
- 子树是序列中连续一段
- 树上路径由 O(logN) 个区间组成
SPOJ QTREE Query on a tree
You are given a tree (an acyclic undirected connected graph)with N nodes, and edges numbered 1, 2, 3 . . . N - 1.We will ask you to perfrom some instructions of the following
form:
- CHANGE i ti : change the cost of the i-th edge to ti
- QUERY a b : ask for the maximum edge cost on the pathfrom node a to node b
- 给定一棵n个节点的树,有两个操作:
- CHANGE i ti 把第i条边的边权变成ti
- QUERY a b 输出从a到b的路径中最大的边权,当a=b的时候,输出0
几个需要注意的点:
1.线段树建树是在dfn序的基础上。
2.查询的时候记得找lca;
#include<bits/stdc++.h>
using namespace std;
const int mxn=100010;
const int mxm=200010;
int dep[mxn],dfn[mxn],fat[mxn];
int top[mxn],son[mxn];
int size[mxn],head[mxn],num[mxn];
int n,cntt;
struct Node{
int u,v,w;
}e[mxm];
struct node{
int to,nxt,dis;
}ed[mxm];
struct nd{
int l,r,val;
}tr[mxm<<2];
void add(int from,int to){
++cntt;
ed[cntt].to=to;
ed[cntt].nxt=head[from];
head[from]=cntt;
}
void dfs1(int u,int fa){
dep[u]=dep[fa]+1;
size[u]=1;
fat[u]=fa;
son[u] = 0;
for(int i=head[u],v;i;i=ed[i].nxt){
v=ed[i].to;
if(v!=fa) {
dfs1(v,u);
size[u]+=size[v];
if (size[v] > size[son[u]])
son[u] = v;
}
}
}
int cnt;
void dfs2(int u,int fa){
dfn[u]=++cnt;
if(son[fa]==u) top[u]=top[fa];
else top[u]=u;
if(son[u]) dfs2(son[u],u);
for(int i=head[u];i;i=ed[i].nxt){
int v=ed[i].to;
if(v!=fa&&v!=son[u]) dfs2(v,u);
}
return;
}
void build(int k,int l,int r){
tr[k].l=l;
tr[k].r=r;
if(l==r){
tr[k].val=num[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tr[k].val=max(tr[k<<1].val,tr[k<<1|1].val);
}
int query(int k,int x,int y){
if(x>y) return 0;
if(tr[k].l==x&&tr[k].r==y)
return tr[k].val;
int mid=(tr[k].r+tr[k].l)>>1;
int ans=0;
if(y<=mid) return query(k << 1, x, y);
if(x>mid) return query(k << 1 | 1, x, y);
else return max(query(k << 1, x, mid), query(k << 1 | 1, mid + 1, y));
}
int getans(int a,int b){
int ret = 0;
while (top[a] != top[b]){
int ta = top[a];
int tb = top[b];
if (dep[ta] > dep[tb])
ret = max(ret, query(1, dfn[ta], dfn[a])), a = fat[ta];
else
ret = max(ret, query(1, dfn[tb], dfn[b])), b = fat[tb];
}
if (dep[a] < dep[b])
swap(a, b);
ret = max(ret, query(1, dfn[b] + 1, dfn[a]));
return ret;
}
void change(int k,int p,int w){
if(tr[k].l==tr[k].r){
tr[k].val=w;
return;
}
int mid=(tr[k].l+tr[k].r)>>1;
if(p<=mid) change(k<<1,p,w);
else change(k<<1|1,p,w);
tr[k].val=max(tr[k<<1].val,tr[k<<1|1].val);
return;
}
int main(){
scanf("%d",&n);
int u,v,w;
for(int i=1;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
e[i].u=u;
e[i].v=v;
e[i].w=w;
add(u,v);add(v,u);
}
dfs1(1,0);
dfs2(1,0);
num[1]=0;//因为是将边权赋给到达点,而dfn序中的第一个显然是没有入度的,那么就是0;
for(int i=1;i<n;i++){
if(dep[e[i].u]>dep[e[i].v])
num[dfn[e[i].u]]=e[i].w;
else
num[dfn[e[i].v]]=e[i].w;
}
build(1,1,n);
char s[100];
int a,b,i,it;
while(1){
scanf("%s",s);
if(s[0]=='D') break;
if(s[0]=='Q'){
scanf("%d%d",&a,&b);
printf("%d\n",getans(a,b));
}
if(s[0]=='C'){
scanf("%d%d",&i,&it);
if(dep[e[i].u]>dep[e[i].v])
change(1,dfn[e[i].u],it);
else
change(1,dfn[e[i].v],it);
}
}
return 0;
}
树链剖分 + 线段树维护区间最大值
BZOJ 4034
有一棵点数为 N 的树,以点 1 为根,且树点有权。然后有 M个操作,分为三种:
- 把某个节点 x 的点权增加 a 。
- 把某个节点 x 为根的子树中所有点的点权都增加 a 。
- 询问某个节点 x 到根的路径中所有点的点权和。
树链剖分 + 线段树单点加、区间加、区间求和
BZOJ 2243 染色
给定一棵有 n 个节点的无根树和 m 个操作,操作有 2 类:
将节点 a 到节点 b 路径上所有点都染成颜色 c
询问节点 a 到节点 b 路径上的颜色段数量(连续相同颜色被认为是同一段),例:“112221”由 3 段组成:“11”、“222”和“1”。
请你写一个程序依次完成这 m 个操作。
树链剖分 + 线段树
- 维护子区间内颜色段树数
- 合并时判断左子区间最右点和右子区间最左点颜色是否相同
- 树链剖分查询答案时还要判断上一条链和本条链相邻结点颜色是否相同
BZOJ 2238 MST
给出一个 N 个点 M 条边的无向带权图,以及 Q 个询问,每次询问在图中删掉一条边后图的最小生成树。 (各询问间独立,每次询问不对之后的询问产生影响,即被删掉的边在下一条询问中依然存在)
如果不在最小生成树上,显然不会产生影响;
如果在最小生成树上,树被分成了两块,寻找权值最小的非树边来代替删去的边;
强连通分量
在有向图中,如果两个点之间存在两个方向的路径,则称两个点强连通;如果有向图的任何两个顶点都强连通,则称其为强连通图;有向图的极大强连通子图即为强连通分量。
缩点
强连通分量最常见的用途是将能互相到达的点集缩为一个新的点,建立的新图一定是有向无环图。
Tarjan 算法
Tarjan 算法可以在 O(N + M) 的时间复杂度内求解有向图的所有强连通分量。
首先提取出有向图的一棵搜索树作为基础框架。
$d f n_u $为 u 点的 DFS 时间戳
\(low_u\) 为 u 点出发能追溯到的最小时间戳
\(low_u=min(dfn_u,low_{v1},dfn_{v2})\)
其中\(<u,v_1>\)为树枝边,\(<u,v_2>\)为后向边
BZOJ 2208 连通数
度量一个有向图的连通情况的一个指标是连通数,指图中可达的顶点对数量。
例如下图中连通数为 14。
现希望求出给定图的连通数。
N ≤ 2000
一个scc内的点互相可达,对答案的贡献:\(k^2\)(自己到自己也算w)
把每个scc缩成一个点,然后变成了DAG,拓扑排序,求每个scc可以到达哪个scc;
对每个点i建一个长度为2000的bitset,其中的第k位的1/0值表示编号为i的点能否到达点k。然后结果就是:
\(\sum\limits_{i=1}^{连通块数量}size[i](\sum\limits_{k=1}^{连通块数量}size[k]) \ \ 其中,bit_i[k]=1;\)
\(bit_i\)表示第i个连通块的bitset,size[i]表示此连通块有几个点;
bitset压位???
bitset:
bitset<100000> a; //长度为10^5的二进制数ww;
bitset<100000> b;
//下标a[0~99999];
//可以赋值,可以访问,支持位运算:a&b
a.set();
a.reset();
a.count();//有多少位是1
POJ 2186 Popular Cows
每头牛都有一个梦想:成为一个群体中最受欢迎的名牛!在一个有 N(1 ≤ N ≤ 10000) 头牛的牛群中,给你 M(1 ≤ M ≤ 50000)个二元组 (A,B), 表示 A 认为 B 是受欢迎的。既然受欢迎是可传递的,那么如果 A 认为 B 受欢迎, B 又认为 C 受欢迎, 则 A 也会认为 C 是受欢迎的,哪怕这不是〸分明确的规定。你的任务是计算被所有其它的牛都喜欢的牛的个数
显然做过www,直接gugu没意见叭
POJ 1236 Network of Schools
给定 N 所学校和网络,每个学校收到软件后会分发给相邻的学校(单向边)。
求:
- 若选取一些学校分发软件使得所有学校都可收到,所需最少分发学校数
- 若要使任选一所学校分发软件,所有学校都可收到,最少新增边数
1.选所有入度为0的点;
2.先化成DAG,算入度为0的点有多少个,出度为0的点有多少个,取更大的就是答案w;