• MST(最小生成树+倍增)


    题目描述:

    给定一个n个点m条边的连通图,保证没有自环和重边。对于每条边求出,在其他边权值不变的情况下,它能取的最大权值,使得这条边在连通图的所有最小生成树上。假如最大权值为无限大,则输出-1。

    题解:

    先求出图的一棵最小生成树:

    对于不在树上的边(x,y), 它的权值只要小于树上x到y路径中一条边就可以代替这条边。

    对于在树上的边(x,y),可以先预处理出所有两端在x到y路径上的不在树上的边的最小值。它的权值一定要小于最小值。

    路径max和min都可以用倍增求。 

    时间复杂度O(nlogn)

    #include<bits/stdc++.h> 
    using namespace std;
    const int N=2e5+5;
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}  
        return x*f;
    }
    int n,m,cnt=0,head[N];
    int vis[N],ans[N];
    int fa[N],dep[N],id[N];
    int f[N][20],maxn[N][20];
    struct data{
        int x,y,dis,id;
    }a[N];
    struct Edge{
        int v,w,nxt,id;
    }edge[N<<1];
    void add_edge(int u,int v,int w,int id){
        edge[++cnt].v=v;edge[cnt].w=w;edge[cnt].id=id;edge[cnt].nxt=head[u];head[u]=cnt;
    }
    int find(int x){
        if(fa[x]==x) return fa[x];
        else return fa[x]=find(fa[x]);
    }
    bool cmp(data a,data b){
        return a.dis<b.dis;
    }
    void build(){
        sort(a+1,a+m+1,cmp);
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=m;i++){
            int x=a[i].x;
            int y=a[i].y;
            if(find(x)!=find(y)){
                fa[find(x)]=find(y);
                vis[a[i].id]=1;
                add_edge(x,y,a[i].dis,a[i].id);
                add_edge(y,x,a[i].dis,a[i].id);
            }
        }
    }
    void dfs(int u){
        for(int i=1;i<=18;i++){
            f[u][i]=f[f[u][i-1]][i-1];
            maxn[u][i]=max(maxn[u][i-1],maxn[f[u][i-1]][i-1]);
        }
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].v;
            int w=edge[i].w;
            if(v==f[u][0]) continue;
            dep[v]=dep[u]+1;
            id[v]=edge[i].id;
            f[v][0]=u;
            maxn[v][0]=w;
            dfs(v);
        }
    }
    void solve(int x,int y,int dis){
        x=find(x);
        while(dep[x]>dep[y]){
            ans[id[x]]=min(ans[id[x]],dis-1);
            int k=find(f[x][0]);
            fa[x]=k;
            x=find(x);
        }
    }
    int get(int x,int y,int &lca){
        int ans=0;
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=18;i>=0;i--)
            if(dep[f[x][i]]>=dep[y]){
                ans=max(ans,maxn[x][i]);
                x=f[x][i];
            }
        if(x==y){
            lca=x;
            return ans;
        }
        for(int i=18;i>=0;i--){
            if(f[x][i]!=f[y][i]){
                ans=max(ans,maxn[x][i]);
                ans=max(ans,maxn[y][i]);
                x=f[x][i],y=f[y][i];
            }
        }
        lca=f[x][0];
        return max(ans,max(maxn[x][0],maxn[y][0]));
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<=m;i++){
            a[i].x=read();a[i].y=read();a[i].dis=read();
            ans[i]=2e9; a[i].id=i;
        }
        build();dfs(1);
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=m;i++){
            if(!vis[a[i].id]){
                int x=a[i].x,y=a[i].y,z;
                ans[a[i].id]=get(x,y,z)-1;
                solve(x,z,a[i].dis);
                solve(y,z,a[i].dis);
            }
        }
        for(int i=1;i<=m;i++){
            if(ans[i]==2e9) printf("-1 ");
            else printf("%d ",ans[i]);
        }
    }
  • 相关阅读:
    error MSB8031(将vs2010的工程用vs2013打开时出的错)
    MFC如何使控件大小随着对话框大小自动调整
    基于MFC对话框程序中添加菜单栏 (CMenu)
    mfc改变对话框窗口大小
    MFC设置对话框大小
    uart与usart区别
    uart接口介绍和认识
    USB引脚属性
    使用百度云服务器BCC搭建网站,过程记录
    linux下文件的复制、移动与删除命令为:cp,mv,rm
  • 原文地址:https://www.cnblogs.com/HarryPotter-fan/p/11378840.html
Copyright © 2020-2023  润新知