【JZOJ4596】Stree

来源:互联网 发布:java集合有几种 编辑:程序博客网 时间:2024/05/16 06:48

Description

给出n个点,m条有权边,现对于每一条边,你需要回答出包含这条边的最小生成树的总边权值。

原题在:CF609E

Solution

对原图做一遍最小生成树,那么在最小生成树上的边答案就是该最小生成树边权和。

原图没有重边,这说明任选n1条不构成环的边都可以构成生成树。

对于不在最小生成树上的边(u,v),我们知道树中最短路径是唯一的,如果添加了(u,v),那么就会生成环,这时我们只要删掉原最小生成树上的u>v路径上最大的边,就可以再次将原图变为包含(u,v)的最小生成树。

运用树上倍增算法可以达到O(nlog2n)

Code

#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)#define N 200001#define M 400001#define ll long longusing namespace std;struct node{    int u,v,w,t;}b[N];int f[N];int wz[N];ll c[N];int to[M],next[M],last[M],val[M],num=0;int fa[N][21],mx[N][21];int d[N];void link(int x,int y,int c){    num++;    to[num]=y;    next[num]=last[x];    last[x]=num;    val[num]=c;}bool cmp(node x,node y){    return x.w<y.w;}int find(int x){    return !f[x]?x:f[x]=find(f[x]);}void dfs(int x){    for(int i=last[x];i;i=next[i])    {        int v=to[i];        if(v!=fa[x][0])        {            fa[v][0]=x;            mx[v][0]=val[i];            d[v]=d[x]+1;            dfs(v);        }    }}int work(int x,int y){    if(d[x]<d[y]) swap(x,y);    int tmp=0;    fd(i,20,0)    if(fa[x][i] && d[fa[x][i]]>=d[y])    tmp=max(tmp,mx[x][i]),x=fa[x][i];    fd(i,20,0)    if(fa[x][i]!=fa[y][i] && fa[x][i] && fa[y][i])    {        tmp=max(tmp,mx[x][i]);        x=fa[x][i];        tmp=max(tmp,mx[y][i]);        y=fa[y][i];    }    if(x!=y)    {        tmp=max(tmp,mx[x][0]);        tmp=max(tmp,mx[y][0]);    }    return tmp;}int main(){    freopen("street.in","r",stdin);    freopen("street.out","w",stdout);    int n,m;    cin>>n>>m;    fo(i,1,m)    {        scanf("%d %d %d",&b[i].u,&b[i].v,&b[i].w);        b[i].t=i;    }    sort(b+1,b+m+1,cmp);    fo(i,1,m) wz[b[i].t]=i;    int z=0;    ll tt=0;    fo(i,1,m)    {        int fx=find(b[i].u),fy=find(b[i].v);        if(fx!=fy)        {            link(b[i].u,b[i].v,b[i].w);            link(b[i].v,b[i].u,b[i].w);            f[fy]=fx;            tt+=b[i].w;            c[b[i].t]=-1;            z++;            if(z==n-1) break;        }    }    fo(i,1,m)    if(c[i]<0) c[i]=tt;    d[0]=-1;    dfs(1);    fo(j,1,20)    fo(i,1,n)    {        fa[i][j]=fa[fa[i][j-1]][j-1];        mx[i][j]=max(mx[i][j-1],mx[fa[i][j-1]][j-1]);    }    fo(q,1,m)    if(!c[q])    {        int u=b[wz[q]].u,v=b[wz[q]].v,w=b[wz[q]].w;        int zz=work(u,v);        c[q]=tt-zz+w;    }    fo(i,1,m) printf("%lld\n",c[i]);}
1 0
原创粉丝点击