Educational Codeforces Round 3 E (609E) Minimum spanning tree for each edge

题意:一个无向图联通中,求包含每条边的最小生成树的值(无自环,无重边)

分析:求出这个图的最小生成树,用最小生成树上的边建图

对于每条边,不外乎两种情况

1:该边就是最小生成树上的边,那么答案显然

2:该边不在最小生成树上,那么进行路径查询,假设加入这条边,那么形成一个环,删去这个环上除该边外的最大权值边,形成一棵树

树的权值即为答案。(并不需要真正加入这条边)

注:其实用树链剖分和LCA都可以,选择自己熟悉的写就行,我写的树链剖分

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn=200005;
int n,m;
LL mst;
struct Edge
{
    int w,v,next;
} edge[maxn<<1];
struct E
{
    int u,v,w,id,mark;
    void init(int a,int b,int c,int d)
    {
        u=a,v=b,w=c,id=d,mark=0;
    }
} o[maxn];
bool cmp1(E a,E b)
{
    return a.id<b.id;
}
bool cmp2(E a,E b)
{
    return a.w<b.w;
}
int head[maxn],p;
void addedge(int u,int v,int w)
{
    edge[p].v=v;
    edge[p].w=w;
    edge[p].next=head[u];
    head[u]=p++;
}
int fa[maxn],sz[maxn],id[maxn],dep[maxn],top[maxn],son[maxn],clk;
int ww[maxn],re[maxn];
void dfs1(int u,int f,int d)
{
    fa[u]=f;
    sz[u]=1;
    son[u]=-1;
    dep[u]=d;
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==f)continue;
        dfs1(v,u,d+1);
        sz[u]+=sz[v];
        if(son[u]==-1||sz[v]>sz[son[u]])
            son[u]=v,re[u]=edge[i].w;
    }
}
void dfs2(int u,int tp,int cc)
{
    id[u]=++clk;
    top[u]=tp;
    ww[id[u]]=cc;
    if(son[u]!=-1)dfs2(son[u],tp,re[u]);
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==son[u]||v==fa[u])continue;
        dfs2(v,v,edge[i].w);
    }
}
int maxw[maxn<<2];
void pushup(int rt)
{
    maxw[rt]=max(maxw[rt*2],maxw[rt*2+1]);
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        maxw[rt]=ww[l];
        return;
    }
    int m=(l+r)>>1;
    build(rt*2,l,m);
    build(rt*2+1,m+1,r);
    pushup(rt);
}
int query(int rt,int l,int r,int x,int y)
{
    if(x<=l&&r<=y)
        return maxw[rt];
    int m=(l+r)>>1;
    int ans=-1;
    if(x<=m)ans=max(ans,query(rt*2,l,m,x,y));
    if(y>m)ans=max(ans,query(rt*2+1,m+1,r,x,y));
    return ans;
}
int getans(int u,int v)
{
    int ans=-1;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]])swap(u,v);
        ans=max(ans,query(1,1,n,id[top[u]],id[u]));
        u=fa[top[u]];
    }
    if(dep[u]>dep[v])swap(u,v);
    ans=max(ans,query(1,1,n,id[son[u]],id[v]));
    return ans;
}
int fat[maxn];
int find(int x)
{
    if(x==fat[x])return x;
    return fat[x]=find(fat[x]);
}
void init()
{
    for(int i=1; i<=n; ++i)
        fat[i]=i;
    mst=p=clk=0;
    memset(head,-1,sizeof(head));
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=0; i<m; ++i)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            o[i].init(u,v,w,i);
        }
        sort(o,o+m,cmp2);
        int cnt=0;
        for(int i=0; i<m; ++i)
        {
            int fx=find(o[i].u);
            int fy=find(o[i].v);
            if(fy==fx)continue;
            addedge(o[i].u,o[i].v,o[i].w);
            addedge(o[i].v,o[i].u,o[i].w);
            cnt++;
            o[i].mark=1;
            fat[fy]=fx;
            mst+=o[i].w;
            if(cnt>=n-1)break;
        }
        dfs1(1,-1,1);
        dfs2(1,1,0);
        build(1,1,n);
        sort(o,o+m,cmp1);
        for(int i=0; i<m; ++i)
        {
            if(o[i].mark)printf("%I64d\n",mst);
            else
            {
                int tt=getans(o[i].u,o[i].v);
                printf("%I64d\n",mst-tt+o[i].w);
            }
        }
    }
    return 0;
}

时间: 2024-10-10 12:21:04

Educational Codeforces Round 3 E (609E) Minimum spanning tree for each edge的相关文章

cf 609E.Minimum spanning tree for each edge

最小生成树,lca(树链剖分(太难搞,不会写)) 问存在这条边的最小生成树,2种情况.1.这条边在原始最小生成树上.2.加上这条半形成一个环(加上),那么就找原来这条边2端点间的最大边就好(减去).(sum+val-max) (代码冗长) 1 #include<bits/stdc++.h> 2 #define LL long long 3 #define N 100005 4 using namespace std; 5 inline int ra() 6 { 7 int x=0,f=1; c

CF609E. Minimum spanning tree for each edge

题解:随便构造一颗最小生成树 然后对于其他不在树上的边  考虑到 删除这条链上的最大值在把这条边加上去 能得到这条边所在的最小生成树 可以LCT维护 但是明显这个题是静态的树就没必要LCT 当然我觉得最优的是树剖以后ST nlogn的的复杂度 也可以树剖+线段树nlog^2的复杂度 #include <bits/stdc++.h> const int MAXN=2e5+10; #define ll long long using namespace std; ll read(){ ll x=0

Minimum spanning tree for each edge

Connected undirected weighted graph without self-loops and multiple edges is given. Graph contains n vertices and m edges. For each edge (u,?v) find the minimal possible weight of the spanning tree that contains the edge (u,?v). The weight of the spa

Educational Codeforces Round 36 (Rated for Div. 2)

Educational Codeforces Round 36 (Rated for Div. 2) F. Imbalance Value of a Tree You are given a tree T consisting of n vertices. A number is written on each vertex; the number written on vertex i is ai. Let's denote the function I(x,?y) as the differ

Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes

Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes 题目连接: http://codeforces.com/contest/985/problem/E Description Mishka received a gift of multicolored pencils for his birthday! Unfortunately he lives in a monochrome w

Educational Codeforces Round 62 (Rated for Div. 2)

layout: post title: Educational Codeforces Round 62 (Rated for Div. 2) author: "luowentaoaa" catalog: true tags: mathjax: true - codeforces - dp --- " target="_blank" style="font-size:24px;">传送门 D - Minimum Triangulat

Educational Codeforces Round 85 (Rated for Div. 2)

Educational Codeforces Round 85 (Rated for Div. 2) A. Level Statistics 签到题, 要求第一位维单增, 第二维变化比第一维慢, 直接模拟即可 B. Middle Class 题目大意 每个人有一些财富, 财富值超过x的人称为富人, 由于实行共产主义, 你可以将某些人的财产重新分配使得富人最多 解题思路 直接按财富值排序, 从大到小加入富人集合, 如果当前富人集合财富平均值小于x就break掉 C. Circle of Monst

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Educational Codeforces Round 26 D. Round Subset(dp)

题目链接:Educational Codeforces Round 26 D. Round Subset 题意: 给你n个数,让你选其中的k个数,使得这k个数的乘积的末尾的0的个数最大. 题解: 显然,末尾乘积0的个数和因子2和因子5的个数有关. 然后考虑dp[i][j]表示选i个数,当前因子5的个数为j时,能得到因子2最多的为多少. 那么对于每个数,记录一下因子2和5的个数,做一些01背包就行了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) me