Street

来源:互联网 发布:手机制作漫画软件 编辑:程序博客网 时间:2024/05/18 00:13

Description

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

Solution

题解和题意一样简洁系列。
首先求出mst,然后对于每一条不在mst里面的边,相当于把它和mst中的一条边替换。
若是(x,y)这条边,那么就是在生成树中x到y的路径上选择一条边权最大的边替换。
倍增最大值即可。

Code

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define rep(i,a) for(int i=last[a];i;i=next[i])#define N 200005using namespace std;typedef long long ll;struct note{int x,y,v,id;}e[N];bool cmp(note x,note y) {return x.v<y.v;}int n,m,x,y,z,tot,cnt,l,q[N],ask[N],d[N],fa[N];int last[N],v[N*2],next[N*2],t[N*2],f[N][18],g[N][18];bool bz[N];ll ans,an[N];int get(int x) {return fa[x]?fa[x]=get(fa[x]):x;}void add(int x,int y,int z) {    t[++l]=y;v[l]=z;next[l]=last[x];last[x]=l;}int lca(int x,int y) {    if (d[x]<d[y]) swap(x,y);int ans=0;    fd(j,17,0) if (d[g[x][j]]>d[y]) ans=max(ans,f[x][j]),x=g[x][j];    if (d[x]!=d[y]) ans=max(ans,f[x][0]),x=g[x][0];    fd(j,17,0) if (g[x][j]!=g[y][j])     ans=max(ans,max(f[x][j],f[y][j])),x=g[x][j],y=g[y][j];    if (x!=y) return max(ans,max(f[x][0],f[y][0]));else return ans;}int main() {    freopen("street.in","r",stdin);    freopen("street.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,m) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v),e[i].id=i;    sort(e+1,e+m+1,cmp);    fo(i,1,m) {        int a=get(e[i].x),b=get(e[i].y);        if (a!=b) fa[a]=b,tot++,ans+=(ll)e[i].v,bz[i]=1;        if (tot==n-1) break;    }    fo(i,1,m) if (bz[i]) {        add(e[i].x,e[i].y,e[i].v);        add(e[i].y,e[i].x,e[i].v);        an[e[i].id]=ans;    } else ask[++cnt]=i;    int i=0,j=1;q[1]=d[1]=1;    while (i<j)         rep(k,q[++i]) if (t[k]!=g[q[i]][0]) {            g[t[k]][0]=q[i];f[t[k]][0]=v[k];            d[t[k]]=d[q[i]]+1;q[++j]=t[k];        }     fo(j,1,17) fo(i,1,n) g[i][j]=g[g[i][j-1]][j-1],    f[i][j]=max(f[i][j-1],f[g[i][j-1]][j-1]);    fo(i,1,cnt) {        int id=ask[i];        an[e[id].id]=ans+(ll)e[id].v;        an[e[id].id]-=(ll)lca(e[id].x,e[id].y);    }    fo(i,1,m) printf("%lld\n",an[i]);}
0 0
原创粉丝点击