題意:給出乙個圖和他的最短路樹,讓你求不經過最短路最後一條邊的最短路。
。。一開始以為直接上次短路,後來發現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有且僅有一條路徑,且這條路徑...