日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

BZOJ 1977: [BeiJing2010组队]次小生成树(Kruskal+树上倍增)

發(fā)布時間:2025/6/17 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ 1977: [BeiJing2010组队]次小生成树(Kruskal+树上倍增) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1977: [BeiJing2010組隊] 次小生成樹 Tree

  Time Limit: 10 Sec
  Memory Limit: 512 MB

Description

  小 C 最近學(xué)了很多最小生成樹的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正當(dāng)>小 C 洋洋得意之時,小 P 又來潑小 C 冷水了。小 P 說,讓小 C 求出一個無向圖的次小生成
樹,而且這個次小生成樹還得是嚴(yán)格次小的,也就是說: 如果最小生成樹選擇的邊集是 >EM,嚴(yán)格次小生成樹選擇的邊集是 ES,那么需要滿足:
  
            
這下小 C 蒙了,他找到了你,希望你幫他解決這個問題。
  

Input

  第一行包含兩個整數(shù)N 和M,表示無向圖的點數(shù)與邊數(shù)。 接下來 M行,每行 3個數(shù)x y z >表示,點 x 和點y之間有一條邊,邊的權(quán)值為z。。
  

Output

  包含一行,僅一個數(shù),表示嚴(yán)格次小生成樹的邊權(quán)和。(數(shù)據(jù)保證必定存在嚴(yán)格次小生成樹)
  

Sample Input 1

  5 6
  1 2 1
  1 3 2
  2 4 3
  3 5 4
  3 4 3
  4 5 6
  

Sample Output 1

  11
  

HINT

  數(shù)據(jù)中無向圖無自環(huán);
  50% 的數(shù)據(jù)N≤2 000 M≤3 000;
  80% 的數(shù)據(jù)N≤50 000 M≤100 000;
  100% 的數(shù)據(jù)N>≤100 000 M≤300 000 ,邊權(quán)值非負(fù)且不超過 10^9 。
  

題目地址: BZOJ 1977: [BeiJing2010組隊]次小生成樹

題解:

     
  先求出最小生成樹,然后枚舉每條不在該樹上的邊  
  求出此邊兩點的樹上路徑中小于此邊長度的最大的邊(題目要求嚴(yán)格次小
  可用樹上倍增解決,因為最大的邊可能等于枚舉的邊,所以還要求出嚴(yán)格次大的邊
  雖然很水但我還是被優(yōu)先級和初值坑了三個小時QWQ
www.cnblogs.com/AGFghy/


AC代碼

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; struct path {int x,y,l; }p[300005]; int n,m,num,f1,f2; ll now,sum,n1,n2,ans; int point[200005],len[200005],Next[200005],head[100005],fa[100005],dep[100005],mark[100005],f[100005][25]; ll mx1[100005][25],mx2[100005][25]; bool cmp(path p1,path p2) {return p1.l<p2.l; } int find(int k) {if (k!=fa[k]) return fa[k]=find(fa[k]);return k; } void add(int u,int v,int nl) {num++;point[num]=v;len[num]=nl;Next[num]=head[u];head[u]=num; } void find(int now,int pre) {dep[now]=dep[pre]+1;f[now][0]=pre;for (int i=head[now]; i!=-1; i=Next[i]){int v=point[i];if (v!=pre) {mx1[v][0]=len[i];find(v,now);}} } ll max(ll x,ll y) {if (x>y) return x;return y; } ll min(ll x,ll y) {if (x<y) return x;return y; } void lca(int u,int v) {if (dep[u]<dep[v]) swap(u,v);int deep=dep[u]-dep[v];for (int i=0; i<=20; i++)if ((deep&(1<<i))>0) {n2=max(n2,mx2[u][i]);if (n1!=mx1[u][i]) n2=max(n2,min(n1,mx1[u][i]));n1=max(n1,mx1[u][i]);u=f[u][i];}for (int i=20; i>=0; i--)if (f[u][i]!=f[v][i]){n2=max(n2,mx2[u][i]);if (n1!=mx1[u][i]) n2=max(n2,min(n1,mx1[u][i]));n1=max(n1,mx1[u][i]);u=f[u][i];n2=max(n2,mx2[v][i]);if (n1!=mx1[v][i]) n2=max(n2,min(n1,mx1[v][i]));n1=max(n1,mx1[v][i]);v=f[v][i];}if (u!=v){n2=max(n2,mx2[u][0]);if (n1!=mx1[u][0]) n2=max(n2,min(n1,mx1[u][0]));n1=max(n1,mx1[u][0]);n2=max(n2,mx2[v][0]);if (n1!=mx1[v][0]) n2=max(n2,min(n1,mx1[v][0]));n1=max(n1,mx1[v][0]);} return; } int main() {scanf("%d%d",&n,&m);for (int i=1; i<=n; i++)head[i]=-1;for (int i=1; i<=m; i++)scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].l);sort(p+1,p+m+1,cmp);for (int i=1; i<=n; i++)fa[i]=i;now=n-1;for (int i=1; i<=m; i++){f1=find(p[i].x);f2=find(p[i].y);if (f1!=f2){now--;fa[f2]=f1;sum+=p[i].l;mark[i]=1;add(p[i].x,p[i].y,p[i].l);add(p[i].y,p[i].x,p[i].l);if (now==0) break;}}memset(mx1,-1,sizeof(mx1));memset(mx2,-1,sizeof(mx2));find(1,0);for (int j=1; j<=20; j++)for (int i=1; i<=n; i++)if (f[i][j-1]){f[i][j]=f[f[i][j-1]][j-1];mx1[i][j]=max(mx1[i][j-1],mx1[f[i][j-1]][j-1]);if (mx1[i][j-1]!=mx1[f[i][j-1]][j-1]) mx2[i][j]=min(mx1[i][j-1],mx1[f[i][j-1]][j-1]);mx2[i][j]=max(mx2[i][j],max(mx2[i][j-1],mx2[f[i][j-1]][j-1]));}ans=1ll<<50;for (int i=1; i<=m; i++)if (mark[i]==0){n1=-1; n2=-1;lca(p[i].x,p[i].y);if (n1!=p[i].l) {now=sum+p[i].l-n1;ans=min(ans,now);}else if (n2!=-1){now=sum+p[i].l-n2;ans=min(ans,now);}}printf("%lld\n",ans);return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/AGFghy/p/9337654.html

總結(jié)

以上是生活随笔為你收集整理的BZOJ 1977: [BeiJing2010组队]次小生成树(Kruskal+树上倍增)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。