bzoj3694 最短路 並查集(樹鏈剖分)

2021-07-31 21:52:43 字數 1626 閱讀 6550

題意:給出乙個圖和他的最短路樹,讓你求不經過最短路最後一條邊的最短路。

。。一開始以為直接上次短路,後來發現zz了,並不可以。。

然後%了一發題解。

其實就是要在最短路樹之外找一條路徑來跑。。

那麼假設現在有一條非樹邊x-y,長度為len。

那麼我們對於t=lca(x,y)(假設y在樹上x不在),可以把1-i的路徑轉化為(i在t到y之間)1-t-x-y-i.

這樣的路徑長度是dis[x]+dis[y]+len-dis[i].

由於最短路固定為只有1條,所以dis[i]固定不變,那麼我們要讓dis[x]+dis[y]+len最短。

所以我們可以用這個值去更新t-y所有點(不包括t)的最短路長度.

可以用線段樹(樹鏈剖分)也可以用並查集。

這裡只講一下並查集。

先把所有非樹邊排個序然後逐個更新。

然後我們發現已經被更新過的點不可能被更新(代價越來越大)。

所以我們可以用並查集維護個已經被更新過的lca。

一點都不覺得樹剖顯然(,可能我比較蠢

#include

#include

#include

#include

#define fo(i,a,b) for(int i=a;i<=b;i++)

#define fd(i,a,b) for(int i=a;i>=b;i--)

using

namespace

std;

const

int n=2e5+5;

int n,m;

int tot,head[n],next[n],go[n],val[n],f[n],cnt;

int fa[n],bel[n],dis[n],h[n];

struct node

edge[n];

inline

void add(int x,int y,int z)

inline

void dfs(int x,int fat,int dep)

}}inline

int find(int x)

inline

bool cmp(node a,node b)

dfs(1,0,1);

fo(i,1,cnt)

edge[i].len=edge[i].l+dis[edge[i].x]+dis[edge[i].y];

sort(edge+1,edge+1+cnt,cmp);

fo(i,1,n)f[i]=i;

fo(i,1,cnt)

else

if (lastx)f[lastx]=x;

lastx=fx;

x=fa[lastx];

fx=find(x);}}

if (bel[2])printf("%d",edge[bel[2]].len-dis[2]);

else

printf("-1");

fo(i,3,n)

if (bel[i])printf(" %d",edge[bel[i]].len-dis[i]);

else

printf(" -1");

return

0;}

最短路樹 BZOJ 3694 最短路

題目傳送門 許可權題警告 顯然可以發現,將1到i路徑上的最後一條路切斷後,需要重新找到一條從i的子樹出發的最短路徑重新回到最短路樹上去.因此考慮一條邊什麼時候會被計算在答案中.設一條邊u v權值為val,只會可能對u,v到 lca u,v 之間的點產生影響.記錄源點1到節點i的距離為dep 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有且僅有一條路徑,且這條路徑...