题目描述
小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) \sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)∑e∈EMvalue(e)<∑e∈ESvalue(e)
这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
输入输出格式
输入格式:
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。
输出格式:
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
输入输出样例
说明
数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
题解
话说这个还没有经典到当模板吧qwq
先做一个最小生成树,图被分成树边和非树边。
在这个树上随便找个点当根,预处理好倍增的东西(包括往上$2^j$步的祖先编号,往祖先走的这条路上最长的边,这条路上第二长的边
然后把每条非树边跑一遍,设两点为$u,v$。
可以想到,从$u$到$v$的这条树上路径中找一条最大但小于这条非树边的边替换,这样的结果是严格次小生成树的一个备选结果。
所以就一边求lca一边跟那一段的最长边和第二长边对比啊什么的。
//记录第二长边主要是防止最长边和这条非树边一样长
作为紫题非常好写,非常不容易错。(毕竟只是倍增lca和Kruscal揉到一起的一个东西,元件都不难写qwq
但确实很长就是了qwq
1 /* 2 qwerta 3 P4180 【模板】严格次小生成树[BJWC2010] Accepted 4 100 5 代码 C++,2.72KB 6 提交时间 2018-10-31 19:50:25 7 耗时/内存 1812ms, 35376KB 8 */ 9 #include<algorithm> 10 #include<iostream> 11 #include<cstring> 12 #include<cstdio> 13 #include<cmath> 14 using namespace std; 15 inline int read() 16 { 17 char ch=getchar(); 18 int x=0; 19 while(!isdigit(ch))ch=getchar(); 20 while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} 21 return x; 22 } 23 const int MAXN=1e5+3,MAXM=3e5+3; 24 struct emm{ 25 int x,y,l,tag; 26 }b[MAXM]; 27 bool cmp(emm qaq,emm qwq){ 28 return qaq.l<qwq.l; 29 } 30 int fa[MAXN]; 31 int fifa(int x) 32 { 33 if(fa[x]==x)return x; 34 return fa[x]=fifa(fa[x]); 35 } 36 struct ahh{ 37 int e,f,l; 38 }a[2*MAXN]; 39 int h[MAXN]; 40 int tot=0; 41 void con(int x,int y,int l) 42 { 43 a[++tot].f=h[x]; 44 h[x]=tot; 45 a[tot].e=y; 46 a[tot].l=l; 47 a[++tot].f=h[y]; 48 h[y]=tot; 49 a[tot].e=x; 50 a[tot].l=l; 51 return; 52 } 53 int w[MAXN],d[MAXN]; 54 void dfs(int x) 55 { 56 for(int i=h[x];i;i=a[i].f) 57 if(!d[a[i].e]) 58 { 59 fa[a[i].e]=x; 60 d[a[i].e]=d[x]+1; 61 w[a[i].e]=a[i].l; 62 dfs(a[i].e); 63 } 64 return; 65 } 66 int f[MAXN][21]; 67 int mac[MAXN][21]; 68 int macc[MAXN][21]; 69 int zz[MAXN]; 70 bool cmpp(int qaq,int qwq){ 71 return qaq>qwq; 72 } 73 int main() 74 { 75 //freopen("a.in","r",stdin); 76 int n=read(),m=read(); 77 for(int i=1;i<=m;++i) 78 { 79 b[i].x=read(),b[i].y=read(),b[i].l=read(); 80 } 81 sort(b+1,b+m+1,cmp); 82 for(int i=1;i<=n;++i) 83 fa[i]=i; 84 int k=n-1,j=0; 85 long long sum=0; 86 while(k) 87 { 88 j++; 89 int u=fifa(b[j].x),v=fifa(b[j].y); 90 if(u!=v) 91 { 92 fa[u]=v; 93 //cout<<b[j].x<<" "<<b[j].y<<" "<<b[j].l<<endl; 94 b[j].tag=1; 95 sum+=b[j].l; 96 con(b[j].x,b[j].y,b[j].l); 97 k--; 98 } 99 } 100 memset(fa,0,sizeof(fa)); 101 int s=min(n,7); 102 d[s]=1; 103 dfs(s); 104 for(int i=1;i<=n;++i) 105 { 106 // /cout<<i<<" "<<fa[i]<<endl; 107 f[i][0]=fa[i]; 108 mac[i][0]=w[i]; 109 } 110 for(int j=1;j<=14;++j) 111 for(int i=1;i+(1<<j)-1<=n;++i) 112 { 113 f[i][j]=f[f[i][j-1]][j-1]; 114 zz[1]=mac[i][j-1],zz[2]=macc[i][j-1]; 115 zz[3]=mac[f[i][j-1]][j-1],zz[4]=macc[f[i][j-1]][j-1]; 116 //cout<<zz[1]<<" "<<zz[2]<<" "<<zz[3]<<" "<<zz[4]<<endl; 117 sort(zz+1,zz+5,cmpp); 118 unique(zz+1,zz+5); 119 mac[i][j]=zz[1]; 120 macc[i][j]=zz[2]; 121 //cout<<i<<" "<<j<<" "<<f[i][j]<<" "<<mac[i][j]<<" "<<macc[i][j]<<endl; 122 } 123 long long ans=1e14+2333; 124 for(int i=1;i<=m;++i) 125 if(!b[i].tag) 126 { 127 int u=b[i].x,v=b[i].y; 128 if(d[u]<d[v])swap(u,v); 129 for(int j=14;j>=0;--j) 130 if(d[u]-d[v]>=(1<<j)) 131 { 132 if(b[i].l>mac[u][j]) 133 ans=min(ans,sum-mac[u][j]+b[i].l); 134 else if(b[i].l==mac[u][j]) 135 ans=min(ans,sum-macc[u][j]+b[i].l); 136 u=f[u][j]; 137 } 138 if(u==v)continue; 139 for(int j=14;j>=0;--j) 140 if(f[u][j]!=f[v][j]) 141 { 142 if(b[i].l>mac[u][j]) 143 ans=min(ans,sum-mac[u][j]+b[i].l); 144 else if(b[i].l==mac[u][j]) 145 ans=min(ans,sum-macc[u][j]+b[i].l); 146 u=f[u][j]; 147 if(b[i].l>mac[v][j]) 148 ans=min(ans,sum-mac[v][j]+b[i].l); 149 else if(b[i].l==mac[v][j]) 150 ans=min(ans,sum-macc[v][j]+b[i].l); 151 v=f[v][j]; 152 } 153 if(b[i].l>w[u]) 154 ans=min(ans,sum-w[u]+b[i].l); 155 if(b[i].l>w[v]) 156 ans=min(ans,sum-w[v]+b[i].l); 157 } 158 cout<<ans<<endl; 159 return 0; 160 }