BZOJ 1977: [BeiJing2010组队]次小生成树(Kruskal+树上倍增)
1977: [BeiJing2010組隊] 次小生成樹 Tree
Time Limit: 10 Sec
Memory Limit: 512 MB
Description
小 C 最近學了很多最小生成樹的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正當>小 C 洋洋得意之時,小 P 又來潑小 C 冷水了。小 P 說,讓小 C 求出一個無向圖的次小生成
樹,而且這個次小生成樹還得是嚴格次小的,也就是說: 如果最小生成樹選擇的邊集是 >EM,嚴格次小生成樹選擇的邊集是 ES,那么需要滿足:
這下小 C 蒙了,他找到了你,希望你幫他解決這個問題。
Input
第一行包含兩個整數N 和M,表示無向圖的點數與邊數。 接下來 M行,每行 3個數x y z >表示,點 x 和點y之間有一條邊,邊的權值為z。。
Output
包含一行,僅一個數,表示嚴格次小生成樹的邊權和。(數據保證必定存在嚴格次小生成樹)
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
數據中無向圖無自環;
50% 的數據N≤2 000 M≤3 000;
80% 的數據N≤50 000 M≤100 000;
100% 的數據N>≤100 000 M≤300 000 ,邊權值非負且不超過 10^9 。
題目地址: BZOJ 1977: [BeiJing2010組隊]次小生成樹
題解:
先求出最小生成樹,然后枚舉每條不在該樹上的邊
求出此邊兩點的樹上路徑中小于此邊長度的最大的邊(題目要求嚴格次小)
可用樹上倍增解決,因為最大的邊可能等于枚舉的邊,所以還要求出嚴格次大的邊
雖然很水但我還是被優先級和初值坑了三個小時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; }轉載于:https://www.cnblogs.com/AGFghy/p/9337654.html
總結
以上是生活随笔為你收集整理的BZOJ 1977: [BeiJing2010组队]次小生成树(Kruskal+树上倍增)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编辑二进制文件
- 下一篇: Informatica ETL work