P4180 【模板】严格次小生成树[BJWC2010]
题目描述
小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 。
又只有90。。。脸黑RE没办法 是我太菜
蓝书上关于生成树的地方讲得还是很清楚的!
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<complex> #define N 400010 #define M 900010 #define INF 214748364700000 #define ll long long using namespace std; ll read() { ll x=0,f=1;char s=getchar(); while(s>'9' || s<'0'){if(s=='-')f=-1;s=getchar();} while(s<='9' && s>='0'){x=x*10+s-'0';s=getchar();} return x*f; } struct edge{ll to,next,v;}a[N<<1]; struct node{ll x,y,v;}e[M]; bool operator < (node a,node b){return a.v<b.v;} ll cnt,head[N],t=0; void add(ll x,ll y,ll v){a[++cnt].to=y;a[cnt].v=v;a[cnt].next=head[x];head[x]=cnt;} ll bz[N][21],deep[N],m1[N][21],m2[N][21],f[N],V[N]; ll find(ll x){if(x==f[x])return x;f[x]=find(f[x]);return f[x];} int n,m; void dfs(ll x,ll fa) { bz[x][0]=fa; for(int i=head[x];i;i=a[i].next) { ll v=a[i].to; if(v==fa)continue; deep[v]=deep[x]+1; m1[v][0]=a[i].v; m2[v][0]=-INF; dfs(v,x); } } void twofold() { for(int i=1;i<=20;i++) for(int j=1;j<=n;j++) { bz[j][i]=bz[bz[j][i-1]][i-1]; m1[j][i]=max(m1[j][i-1],m1[bz[j][i-1]][i-1]); m2[j][i]=max(m2[j][i-1],m2[bz[j][i-1]][i-1]); if(m1[j][i-1]>m1[bz[j][i-1]][i-1])m2[j][i]=max(m2[j][i],m1[bz[j][i-1]][i-1]); else if(m1[j][i-1]<m1[bz[j][i-1]][i-1])m2[j][i]=max(m2[j][i],m1[j][i-1]); } } ll lca(ll x,ll y) { if(deep[x]<deep[y])swap(x,y); for(int i=20;i>=0;i--) if(deep[bz[x][i]]>=deep[y])x=bz[x][i]; if(x==y)return x; for(int i=20;i>=0;i--) if(bz[x][i]!=bz[y][i])x=bz[x][i],y=bz[y][i]; return bz[x][0]; } ll qmax(ll x,ll y,ll d) { ll s=-INF; for(int i=20;i>=0;i--) if(deep[bz[x][i]]>=deep[y]) { if(d!=m1[x][i])s=max(s,m1[x][i]); else s=max(s,m2[x][i]); x=bz[x][i]; } return s; } int main() { n=read();m=read(); for(int i=1;i<=m;i++)e[i].x=read(),e[i].y=read(),e[i].v=read(); sort(e+1,e+m+1); for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=m;i++) { ll p=find(e[i].x),q=find(e[i].y); if(p!=q) { t+=e[i].v;f[p]=q;V[i]=1; add(e[i].x,e[i].y,e[i].v);add(e[i].y,e[i].x,e[i].v); } } deep[1]=1;m2[1][0]=-INF; dfs(1,-1);twofold(); ll ans=INF; for(int i=1;i<=m;i++) if(!V[i]) { ll x=e[i].x,y=e[i].y,d=e[i].v,l=lca(x,y),p; p=t-max(qmax(x,l,d),qmax(y,l,d))+d; ans=min(ans,p); } printf("%lld\n",ans); return 0; }