Educational Codeforces Round 3 E. Minimum spanning tree for each edge MST+树上路径倍增

题目链接:http://codeforces.com/contest/609/problem/E

题意:给一个无向图,n个点,m条边,对任意边edge[i],求出包含有边edge[i]的最小生成树。

解法:考虑MST的性质,对任意两点u,v一定有且只有一条路径,当边[u,v]不是MST边的时候,加入边[u,v]便

会形成环,于是在u到v的路径上找一条权值最大的边删去再加入边[u,v],之前环上的任意两点仍然连通。

u到v路径的最大值用LCA来维护。

//CF 609E

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5+5;
struct edge1{
    int u, v, w, id;
}E1[maxn*2];
struct edge2{
    int v, w, nxt;
}E2[maxn*2];
int head[maxn], edgecnt, n, m;
void init(){
    memset(head, -1, sizeof(head));
    edgecnt=0;
}
void add(int u, int v, int w){
    E2[edgecnt].v = v, E2[edgecnt].w = w,E2[edgecnt].nxt = head[u], head[u] = edgecnt++;
}
int pa[maxn];
int find_set(int x){
    if(x == pa[x]) return x;
    else return pa[x] = find_set(pa[x]);
}
bool cmp(const edge1 &a, const edge1 &b){
    return a.w < b.w;
}
long long build(){
    sort(E1+1, E1+m+1, cmp);
    for(int i=1;i<=n;i++) pa[i]=i;
    int cnt=0;
    long long ans=0;
    for(int i=1; i<=m; i++){
        int x=E1[i].u, y=E1[i].v;
        int fx = find_set(x), fy = find_set(y);
        if(fx==fy) continue;
        add(E1[i].u, E1[i].v, E1[i].w);
        add(E1[i].v, E1[i].u, E1[i].w);
        pa[fx]=fy;
        ans+=E1[i].w;
        cnt++;
        if(cnt==n-1) break;
    }
    return ans;
}


int dep[maxn],p[20][maxn],maxv[20][maxn];
void dfs(int u,int f,int d,int w)
{
    dep[u]=d;
    p[0][u]=f,maxv[0][u]=w;
    for(int i=head[u]; ~i; i=E2[i].nxt)
    {
        int v=E2[i].v;
        if(v==f) continue;
        dfs(v,u,d+1,E2[i].w);
    }
}
void build2()
{
    dfs(1,-1,0,0);
    for(int i=0; i+1<18; i++)
    {
        for(int v=1; v<=n; v++)
        {
            if(p[i][v]<0) p[i+1][v]=-1;
            else p[i+1][v]=p[i][p[i][v]];
            maxv[i+1][v] = max(maxv[i][v],maxv[i][p[i][v]]);
        }
    }
}
int lca(int u,int v)
{
    if(dep[u]>dep[v]) swap(u,v);
    for(int i=0; i<18; i++) if(dep[u]-dep[v]>>i&1) v=p[i][v];
    if(u==v) return u;
    for(int i=17; ~i; i--)
        if(p[i][u]!=p[i][v])
            u=p[i][u],v=p[i][v];
    return p[0][u];
}
int get(int u,int to)
{
    int ret=0;
    for(int i=0; i<18; i++)
        if(dep[u]-dep[to]>>i&1) ret=max(ret,maxv[i][u]),u=p[i][u];
    return ret;
}

long long ans[maxn];

int main()
{
    scanf("%d%d", &n, &m);
    init();
    for(int i=1; i<=m; i++){
        scanf("%d%d%d", &E1[i].u, &E1[i].v, &E1[i].w);
        E1[i].id = i;
    }
    long long mst = build();
    build2();
    for(int i=1; i<=m; i++){
        int _lca = lca(E1[i].u, E1[i].v);
        int xx = max(get(E1[i].u, _lca), get(E1[i].v, _lca));
        ans[E1[i].id] = mst-xx+E1[i].w;
    }
    for(int i=1; i<=m; i++){
        printf("%lld\n", ans[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值