您的位置:首页 > 其它

BZOJ 1977 次小生成树(最近公共祖先)

2016-05-27 20:44 363 查看
题意:求一棵树的严格次小生成树,即权值严格大于最小生成树且权值最小的生成树。

先求最小生成树,对于每个不在树中的边,取两点间路径的信息,如果这条边的权值等于路径中的权值最大值,那就删掉路径中的次大值,加上这条非树边,更新答案;否则删掉路径中的最大值,加上这条非树边,更新答案。

#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define ll long long
struct edge{
int u,v,id;
ll w;
}e[300005];
int tot,go[600005],first[300005],next[600005];
ll val[600005];
int fa[100005][18],deep[100005],F[100005],bin[105],n,m;
ll mx1[100005][18],mx2[100005][18],ans1,ans2;
int read(){
char ch=getchar();int t=0,f=1;
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
return t*f;
}
ll Read(){
char ch=getchar();ll t=0,f=1;
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
return t*f;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
void insert(int x,int y,ll z){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
val[tot]=z;
}
void add(int x,int y,int z){
insert(x,y,z);insert(y,x,z);
}
int find(int x){
if (F[x]==x) return x;
else return (find(F[x]));
}
void up(ll x,ll &y){
if (x>y) y=x;
}
void work(int x,int i){
mx1[x][i]=std::max(mx1[fa[x][i-1]][i-1],mx1[x][i-1]);
if (mx1[fa[x][i-1]][i-1]<mx1[x][i]) up(mx1[fa[x][i-1]][i-1],mx2[x][i]);
if (mx1[x][i-1]<mx1[x][i]) up(mx1[x][i-1],mx2[x][i]);
up(mx2[x][i-1],mx2[x][i]);
up(mx2[fa[x][i-1]][i-1],mx2[x][i]);
}
void dfs(int x,int f){
for (int i=1;i<=17;i++)
fa[x][i]=fa[fa[x][i-1]][i-1],work(x,i);
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (pur==f) continue;
deep[pur]=deep[x]+1;
fa[pur][0]=x;
mx1[pur][0]=val[i];
mx2[pur][0]=0;
dfs(pur,x);
}
}
void up(ll x,ll &a,ll &b){
if (x>a) b=a,a=x;
else
if (x>b&&x<a) b=x;
}
void lca(int x,int y){
ans1=0,ans2=0;
if (deep[x]<deep[y]) std::swap(x,y);
int t=deep[x]-deep[y];
for (int i=0;i<=17;i++)
if (t&bin[i]) {
up(mx1[x][i],ans1,ans2);
up(mx2[x][i],ans1,ans2);
x=fa[x][i];
}
for (int i=17;i>=0;i--)
if (fa[x][i]!=fa[y][i]) {
up(mx1[x][i],ans1,ans2);
up(mx2[x][i],ans1,ans2);
up(mx1[y][i],ans1,ans2);
up(mx2[y][i],ans1,ans2);
x=fa[x][i];
y=fa[y][i];
}
if (x!=y){
up(mx1[x][0],ans1,ans2);
up(mx2[x][0],ans1,ans2);
up(mx1[y][0],ans1,ans2);
up(mx2[y][0],ans1,ans2);
}
}
int main(){
bin[0]=1;
for (int i=1;i<=17;i++) bin[i]=bin[i-1]*2;
n=read();m=read();
for (int i=1;i<=m;i++){
e[i].u=read();
e[i].v=read();
e[i].w=Read();
e[i].id=0;
}
for (int i=1;i<=n;i++)
for (int j=0;j<=17;j++)
mx1[i][j]=mx2[i][j]=0;
std::sort(e+1,e+1+m,cmp);
ll sum=0;
for (int i=1;i<=n;i++) F[i]=i;
for (int i=1;i<=m;i++)
if (find(e[i].u)!=find(e[i].v)){
F[find(e[i].u)]=find(e[i].v);
e[i].id=1;
add(e[i].u,e[i].v,e[i].w);
sum+=e[i].w;
}
dfs(1,0);
ll Ans=10000000000000000LL;
for (int i=1;i<=m;i++)
if (!e[i].id){
lca(e[i].u,e[i].v);
if (e[i].w==ans1) Ans=std::min(Ans,sum-ans2+e[i].w);
else Ans=std::min(Ans,sum-ans1+e[i].w);
}
printf("%lld\n",Ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: