zoukankan      html  css  js  c++  java
  • 暑假考试题5:tree 最小生成树(最小生成树+倍增)

    题目:

    分析:

    转换问题:先求出一颗最小生成树
    对于非树边来说,连上非树边一定会成环,而可以使非树边成为树边的即是环上max-1
    对于树边来说,它不能无限增大,是由于受到非树边的影响,而答案即为能影响它的非树边的min-1

    第一个只需要求链最大值,用倍增解决
    第二个:对于每一条非树边,都要更新一条链,但是可以不用写链剖
    做法:将非树边从小到大排好序,显然一条边先被小的更新了,就不会被大的更新了,所以开一个ff数组
    表示一个点到深度比它浅的点那条路径(不经过根)已经被更新了 当枚举非树边去更新的时候 把已经被更新的跳过
    保证了每条边只被更新过一次

    /*
    先求出一颗最小生成树
    对于非树边来说,连上非树边一定会成环,而可以使非树边成为树边的即是环上max-1 
    对于树边来说,它不能无限增大,是由于受到非树边的影响,而答案即为能影响它的非树边的min-1
    第一个只需要求链最大值,用倍增解决
    第二个:对于每一条非树边,都要更新一条链,但是可以不用写链剖
    做法:将非树边从小到大排好序,显然一条边先被小的更新了,就不会被大的更新了,所以开一个ff数组
    表示一个点到深度比它浅的点那条路径(不经过根)已经被更新了 当枚举非树边去更新的时候 把已经被更新的跳过
    保证了每条边只被更新过一次 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define inf 1000000001
    #define N 100005
    int head[N],w[N<<1],to[N<<1],nex[N<<1],tot=0,fa[N],ans[N],id[N<<1];
    int f[N][30],mx[N][30],dep[N],num[N],s[N],ff[N],fl[N],n,m;
    struct node{ int u,v,w,o,ans; }e[N];
    bool cmp1(const node &a,const node &b) { return a.w<b.w; }
    bool cmp2(const node &a,const node &b) { return a.o<b.o; }
    void add(int a,int b,int ww,int i) { to[++tot]=b; nex[tot]=head[a]; w[tot]=ww; id[tot]=i; head[a]=tot; }
    int find(int x)
    {
        if(fa[x]==x) return x;
        return fa[x]=find(fa[x]);
    }
    void dfs(int u)
    {
        for(int i=head[u];i;i=nex[i]){
            int v=to[i];
            if(v==f[u][0]) continue;
            f[v][0]=u; dep[v]=dep[u]+1;
            mx[v][0]=w[i]; num[v]=id[i];//id记录这个点向上连的边对应排好序后的编号 
            for(int j=1;j<=20;j++) f[v][j]=f[f[v][j-1]][j-1];
            for(int j=1;j<=20;j++) mx[v][j]=max(mx[f[v][j-1]][j-1],mx[v][j-1]);
            dfs(v);
        }
    }
    int lca(int a,int b)
    {
        if(dep[a]>dep[b]) swap(a,b);
        for(int i=20;i>=0;i--) if(dep[f[b][i]]>=dep[a]) b=f[b][i];//=!!
        if(a==b) return a;
        for(int i=20;i>=0;i--) if(f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];
        return f[a][0];
    }
    int lca_max(int a,int b,int lc)
    {
        int anss=-1;
        if(dep[a]>dep[b]) swap(a,b);
        for(int i=20;i>=0;i--) if(dep[f[b][i]]>=dep[a]) anss=max(anss,mx[b][i]),b=f[b][i];//先更新再跳 一定要有dep>=!! 
        if(a==b) return anss;
        for(int i=20;i>=0;i--) if(f[a][i]!=f[b][i]) anss=max(anss,max(mx[a][i],mx[b][i])),a=f[a][i],b=f[b][i];
        anss=max(anss,max(mx[a][0],mx[b][0]));
        return anss;
    }
    void work(int u,int lc,int ww)
    {
        while(dep[u]>dep[lc]){
            if(!s[num[u]] || s[num[u]]>ww) s[num[u]]=ww;//更新最小值 
            ff[u]=lc; u=f[u][0];//记录u已经更新到哪一个点了 u一定要=fa[u] 否则会在原地不动 
            while(ff[u]!=u) u=ff[u];
        }
    }
    int main()
    {
        freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
        int a,b,ww;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&ww);
            e[i].u=a,e[i].v=b,e[i].w=ww,e[i].o=i;
        }
        sort(e+1,e+1+m,cmp1);
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=m;i++){
            int f1=find(e[i].u),f2=find(e[i].v);
            if(f1==f2) continue;
            fa[f1]=f2; fl[i]=1; 
            add(e[i].u,e[i].v,e[i].w,i); add(e[i].v,e[i].u,e[i].w,i);
        }
        dep[1]=1;
        dfs(1);
        for(int i=1;i<=n;i++) ff[i]=i;//ff数组记录每个点更新到哪一个点了 初始时为它自己  
        for(int i=1;i<=m;i++){
            if(fl[i]) continue;
            int u=e[i].u,v=e[i].v,ww=e[i].w;
            int lc=lca(u,v),maxx=lca_max(u,v,lc);
            ans[i]=maxx-1;//ans存储非树边的值 
            while(ff[u]!=u) u=ff[u];//直接跳到已经更新到的位置 
            while(ff[v]!=v) v=ff[v];
            work(u,lc,ww);//处理将u到v的一条链更新成最小的非树边的值 
            work(v,lc,ww);
        }
        for(int i=1;i<=m;i++){
            if(!fl[i]) e[i].ans=ans[i];
            else e[i].ans=s[i]-1;
        }
        sort(e+1,e+1+m,cmp2);
        for(int i=1;i<=m;i++) printf("%d
    ",e[i].ans);/**/
    }
    /*
    4 4 
    2 1 2 
    3 2 2 
    4 3 2 
    1 4 3
    
    7 8
    1 2 2
    1 4 3
    2 3 6
    2 5 8
    2 7 5
    1 7 9
    3 6 7
    2 4 4
    
    */
  • 相关阅读:
    小试阿里云容器服务
    .NET跨平台:再见dnx,你好dotnet cli
    使用Let's Encrypt手动创建https证书
    Chrome以https访问gitlab的问题:Your connection is not private
    [ASP.NET 5]终于解决:Unable to load DLL 'api-ms-win-core-localization-obsolete-l1-2-0.dll'
    Mac上远程桌面连接Windows Server 2012 R2
    解决JSON.stringify()在IE10下无法使用的问题
    解决阿里云SLB无法添加https证书的问题
    “状态机”学习笔记
    HttpClient读取ASP.NET Web API错误信息的简单方法
  • 原文地址:https://www.cnblogs.com/mowanying/p/11420174.html
Copyright © 2011-2022 走看看