小c最近學了很多最小生成樹的演算法,prim演算法、kurskal演算法、消圈演算法等等。正當小c洋洋得意之時,小p又來潑小c冷水了。小p說,讓小c求出乙個無向圖的次小生成樹,而且這個次小生成樹還得是嚴格次小的,也就是說:如果最小生成樹選擇的邊集是em,嚴格次小生成樹選擇的邊集是es,那麼需要滿足:(value(e)表示邊e的權值)
\[∑e∈emvalue(e)<∑e∈esvalue(e)
\]這下小 c 蒙了,他找到了你,希望你幫他解決這個問題。
第一行包含兩個整數n 和m,表示無向圖的點數與邊數。 接下來 m行,每行 3個數x y z 表示,點 x 和點y之間有一條邊,邊的權值為z。
包含一行,僅乙個數,表示嚴格次小生成樹的邊權和。(資料保證必定存在嚴格次小生成樹)
先kruscal最小生成樹,然後列舉非樹邊,權值為w,將邊的兩端點的路徑(lca)上的最長邊用w替換,但由於我們求的是嚴格次小生成樹,所以當最長邊邊權==w時,需要用嚴格次大邊替代,因此用倍增維護lca上的嚴格次大值和最大值.具體見**注釋:
#define ll long long
#include#include#include#define rg register
using namespace std;
const int n=1e5+5,m=3e5+5;
inline ll read()
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}inline ll min(ll a,ll b)
ll n,m,cnt,num,cost,ans=100000000000000;
ll last[n],par[n],dep[n],f[n][25],f1[n][25],f2[n][25];
//f[i][j]表示i節點2^j祖先的序號,f1[i][j]表示從i到f[i][j]路徑上的最大邊權,f1[i][j]表示嚴格次大邊權.
bool used[m];
struct edgee[2*m];
struct edgme1[m];
void insert(ll u,ll v,ll w)
;last[u]=cnt;
e[++cnt]=(edge);last[v]=cnt;
}bool cmp(edgm a,edgm b)
}if(a!=b)
dwq[++ct]=f1[a][0];
dwq[++ct]=f1[b][0];
dwq[++ct]=f2[a][0];
dwq[++ct]=f2[b][0];
}sort(dwq+1,dwq+ct+1);
for(ll i=ct;i>=1;i--)if(dwq[i]}int main()
; sort(e1+1,e1+m+1,cmp);
kruskal();
init();
for(ll i=1;i<=m;i++)
printf("%lld\n",ans);
return 0;
}
次小生成樹 Tree(倍增)
時間限制 1000 ms 記憶體限制 524288 kb 小 c 最近學了很多最小生成樹的演算法,prim 演算法 kurskal 演算法 消圈演算法等等。正當小 c 洋洋得意之時,小 p 又來潑小 c 冷水了。小 p 說,讓小 c 求出乙個無向圖的次小生成樹,而且這個次小生成樹還得是嚴格次小的,也...
HYSBZ 1977 次小生成樹 Tree
題意 給定乙個有 n 個點 m 條邊的無向帶權圖,求嚴格次小生成樹。n 1e5,m 3e5 解題思路 求非嚴格次小生成樹時,替換路徑上的最大邊,加入的邊權可能與其相等,故倍增時多維護乙個路徑上嚴格的次大值即可。include using namespace std typedef long long...
最小生成樹 Tree
參考資料 description 給你乙個無向帶權連通圖,每條邊是黑色或白色。讓你求一棵最小權的恰好有need條白色邊的生成樹。題目保證有解。input 第一行v,e,need分別表示點數,邊數和需要的白色邊數。接下來e行 每行s,t,c,col表示這邊的端點 點從0開始標號 邊權,顏色 0白色1黑...