最短路樹 BZOJ 3694 最短路

2021-08-28 22:13:43 字數 1652 閱讀 2373

題目傳送門(許可權題警告)

顯然可以發現,將1到i路徑上的最後一條路切斷後,需要重新找到一條從i的子樹出發的最短路徑重新回到最短路樹上去.

因此考慮一條邊什麼時候會被計算在答案中.

設一條邊u->v權值為val,只會可能對u,v到 lca(u,v) 之間的點產生影響.記錄源點1到節點i的距離為dep[i],那麼就可以把答案更新為dep[u]+dep[v]+val-dep[i].

可以預處理出dep,然後對於每一條邊都暴力爬公升至lca更新答案.

時間複雜度:o(n

m)

o(nm)

o(nm

)但是資料可能比較水,沒有生成最壞的資料卡,所以針對隨機資料是o(mlogn)

這樣做顯然不能過掉 (實際能過) ,於是開始優化.首先對於邊,按照dep[u]+dep[v]+val排序,因為dep[i]是隨著點的不同有變化,不用管.

那麼顯然每個點有效的答案只會被第一次到它的邊更新.然後利用並查集,可以維護出乙個點u上次更新到的點.然後每次跳轉到那裡更新,注意判斷是否直接越過了lca.

時間複雜度:o(m

logm

)o(mlogm)

o(mlog

m)只寫了暴力,並查集**以後補

#include

#include

using

namespace std;

const

int maxn=

4005

;const

int maxm=

100005

;const

int inf=

0x3f3f3f3f

;int n,m,ncnt;

int p[maxn]

,dep[maxn]

,vis[maxn]

;int ans[maxn]

;int head[maxn]

,ecnt;

struct edgee[maxm]

;struct nodeg[maxm]

;void

addedge

(int u,

int v,

int val)

; head[u]

=ecnt;

}void

dfs(

int u,

int fa=0)

}int

main()

;}dfs(1)

;for

(int i=

1;i<=ncnt;i++

) g[i]

.val+

=dep[g[i]

.u]+dep[g[i]

.v];

for(

int i=

1;i<=n;i++

) ans[i]

=inf;

for(

int i=

1;i<=ncnt;i++)}

for(

int i=

2;i<=n;i++

)printf

("%s%d"

,i==2?

"":" ",ans[i]

==inf?-1

:ans[i]);

}

bzoj3694 最短路 樹鏈剖分

給出乙個n個點m條邊的無向圖,n個點的編號從1 n,定義源點為1。定義最短路樹如下 從源點1經過邊集t到任意一點i有且僅有一條路徑,且這條路徑是整個圖1到i的最短路徑,邊集t構成最短路樹。給出最短路樹,求對於除了源點1外的每個點i,求最短路,要求不經過給出的最短路樹上的1到i的路徑的最後一條邊。第一...

Bzoj 3694 最短路 樹鏈剖分

time limit 5 sec memory limit 256 mb submit 67 solved 34 submit status discuss 給出乙個n個點m條邊的無向圖,n個點的編號從1 n,定義源點為1。定義最短路樹如下 從源點1經過邊集t到任意一點i有且僅有一條路徑,且這條路徑...

BZOJ 3694 最短路 樹鏈剖分 倍增

下個月就是noip10連測試,還有什麼大學先修課考試,這段時間一直很忙但是還是抽出時間來複習一下版子,前段時間一直在搞spfa的各種建模,這段時間就來複習一下資料結構吧。首先就來不太好打的樹鏈剖分。嗯,開心,就每天寫一點點居然叫了兩遍就ac了,剛準備自己出資料還沒出,就抱著嘗試的想法提交了,居然ac...