bzoj1977 [BeiJing2010组队]次小生成树 Tree (lca+倍增)

来源:互联网 发布:湖北广电网络客服电话 编辑:程序博客网 时间:2024/06/05 06:18

bzoj1977 [BeiJing2010组队]次小生成树 Tree

原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1977

题意:
小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:这里写图片描述
(value(e) 表示边 e的权值)
这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

Input
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

Output

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

Sample Input
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6

Sample Output
11

数据范围
给出的图为无向图且无自环
N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

题解:
(刚发现NOIP考纲上有次小生成树,赶紧来刷掉这道水题)

倍增存向上2^p步内的最大值和严格次大值,及2^p步后跳到的点。

造好最小生成树后枚举不在最小生成树上的边 i,查询在最小生成树上 ui,vi这两个点的路径上不等于 wi 的最大值mx,就在跳祖先求lca时一段一段地更新这个mx。
最后可以求得一个最小增量 mn=min(wi-mxi)

求得 次小生成树上的权值和=最小生成树上权值和 + 最小增量

代码:

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<vector>#define LL long longusing namespace std;const int N=100005;const int M=300005;const int P=18;const int inf=0x3f3f3f3f;vector<int> V;int n,m,fa[N],head[N],to[2*N],nxt[2*N],dep[N],anc[N][P+1],num=0;LL w[2*N],val[N][P+1][2],mn;struct edge{    int u,v;    LL w;}E[M];bool cmp(const edge &A,const edge &B){    return A.w<B.w;}int getfa(int x){    if(fa[x]==x) return x;    else return fa[x]=getfa(fa[x]);}void build(int u,int v,LL ww){    num++;    to[num]=v;    nxt[num]=head[u];    w[num]=ww;    head[u]=num;}void dfs(int u,int f,LL ww){    anc[u][0]=f;    val[u][0][0]=ww;    val[u][0][1]=-inf;    for(int i=1;i<P;i++)    {        anc[u][i]=anc[anc[u][i-1]][i-1];        val[u][i][0]=max(val[u][i-1][0],val[anc[u][i-1]][i-1][0]);        if(val[u][i-1][0]!=val[anc[u][i-1]][i-1][0])        val[u][i][1]=min(val[u][i-1][0],val[anc[u][i-1]][i-1][0]);        else        val[u][i][1]=max(val[u][i-1][1],val[anc[u][i-1]][i-1][1]);    }    for(int i=head[u];i;i=nxt[i])    {        int v=to[i];        if(v==f) continue;        dep[v]=dep[u]+1;        dfs(v,u,w[i]);    }   }void query(int u,int v,LL ww){    LL mx=-inf;    if(dep[u]<dep[v]) swap(u,v);    int d=dep[u]-dep[v];    for(int i=0;d;d>>=1,i++)    {        if(d&1)         {            u=anc[u][i];            LL vv=(val[u][i][0]==ww)? val[u][i][1]:val[u][i][0];            mx=max(mx,vv);        }    }    for(int i=P-1;i>=0;i--)    {        if(anc[u][i]!=anc[v][i])        {            LL vv=(val[u][i][0]==ww)? val[u][i][1]:val[u][i][0];            mx=max(mx,vv);            vv=(val[v][i][0]==ww)? val[v][i][1]:val[v][i][0];            mx=max(mx,vv);            u=anc[u][i]; v=anc[v][i];        }    }    if(val[u][0][0]!=ww) mx=max(mx,val[u][0][0]);    if(val[v][0][0]!=ww) mx=max(mx,val[v][0][0]);    mn=min(mn,ww-mx);}int main(){    memset(head,0,sizeof(head)); num=0;    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)    scanf("%d%d%lld",&E[i].u,&E[i].v,&E[i].w);    sort(E+1,E+m+1,cmp);    for(int i=1;i<=n;i++) fa[i]=i;    int cnt=0;    LL sum=0;    for(int i=1;i<=m;i++)    {        int u=E[i].u; int v=E[i].v;        int fx=getfa(u); int fy=getfa(v);        if(fx==fy) V.push_back(i);        else         {            fa[fx]=fy; sum+=E[i].w;            build(u,v,E[i].w); build(v,u,E[i].w);        }    }    dep[1]=0;    dfs(1,0,0);    int sz=V.size();    mn=inf;    for(int i=0;i<sz;i++)    {        int u=E[V[i]].u; int v=E[V[i]].v; LL ww=E[V[i]].w;             query(u,v,ww);    }    printf("%lld\n",sum+mn);    return 0;}

//我今天很开心(ノ≧∀≦)ノ

阅读全文
0 0
原创粉丝点击