p2023

 

终于a掉了这破题,挣扎了一上午...

克鲁斯卡尔求最小生成树的过程是将边排序后对于所有边用并查集判断两端点是否在一个集合内,如果不在就启用这条边,将两端点连一块,否则就不用.

原理大概是根据定理:"任意一颗最小生成树一定包含无向图中权值最小的边"那么有推论"设G=(V,E)是一个连通网络,U是顶点集V的一个非空真子集.若(u,v)是G中一条"一个端点在U中(例如:u∈U),另一个端点不在U中的边(例如:v∈V-U),且(u,v)具有最小权值,则一定存在G的一棵最小生成树包括此边(u,v).

而对于一个最小生成树,枚举不在最小生成树里的边假装要加入,那么生成的新树一定要删掉在新边的两端点连线间的权值最大边.如果新边的权值就是最大边就去删最小边,因为此时删最大边的到的答案与原最小生成树边权和相同,不是严格次小生成树.

那么预处理出最小生成树后的策略就是枚举所有不在树里的边,查找两端点间最长边zui,如果o[i].v==zui就取查找次长边ci,更新答案为sum-ci+o[i].v.否则更新答案为sum-zui+o[i].v;

那么求两端点间最长边怎么搞呢?似乎可以用类似于lca的方法处理,我会树上倍增!

考虑处理lca的时候顺便处理自己与第2^k的祖先的最长边和严格次长边.最长边很简单啦,g[y][0][0]=e[i].v,g[y][k][0]=max(g[y][k-1][0],g[f[y][k-1]][0]);考虑次长边,g[y][0][1]=-inf,因为没有.

 

如果区间y-f[y][k-1],f[y][k-1],f[k]内部的最长边相等,次长边应该等于两个区间内部的次长边最大值,否则应该等于小的那个最长边和大的那个次长边的最长边..绕口令ing

也可以解释为:首先等于两个次长边的最大边一定没错吧.而如果两个最长边不一样长,还可以选一下最长边中小的那一个.

                g[y][k][1]=max(g[y][k-1][1],g[f[y][k-1]][k-1][1]);
                if(g[y][k-1][0]!=g[f[y][k-1]][k-1][0])
                    g[y][k][1]=max(g[y][k][1],min(g[y][k-1][0],g[f[y][k-1]][k-1][0]));

觉得难了么?一会才更难.

这样预处理完了每个点向上跳2^k次方时的最长边与次长边,求两个不一定在同一个连上的点之间的最长边与次长边该怎么办呢?比较好写的方法是跑两遍.

先处理出最长边,这个直接每次取区间内的最长边就好.(无脑取max);

            for(k=t;k>=0;k--)
                if(d[f[y][k]]>=d[x]){
                    zui=max(zui,g[y][k][0]);
                    y=f[y][k];
                }
            if(x!=y){
                for(k=t;k>=0;k--)
                    if(f[x][k]!=f[y][k]){
                        zui=max(zui,max(g[x][k][0],g[y][k][0]));
                        x=f[x][k],y=f[y][k];
                    }
                zui=max(zui,max(g[y][0][0],g[x][0][0]));
            }

而次长边的时候只要不等于最长边的边都可以取max,可以这样搞一搞

            for(k=t;k>=0;k--)
                if(d[f[y][k]]>=d[x]){
                    if(zui==g[y][k][0])
                        ci=max(ci,g[y][k][1]);
                    else
                        ci=max(ci,g[y][k][0]);
                }
            if(x!=y){
                for(k=t;k>=0;k--){
                    if(zui==max(g[x][k][0],g[y][k][0]))
                    {
                        if(g[x][k][0]==g[y][k][0])
                            ci=max(ci,max(g[y][k][1],g[x][k][1]));
                        if(g[x][k][0]>g[y][k][0])
                            ci=max(ci,max(g[x][k][1],g[y][k][0]));
                        if(g[x][k][0]<g[y][k][0])
                            ci=max(ci,max(g[x][k][0],g[y][k][1]));
                    }
                    else
                        ci=max(ci,max(g[x][k][0],g[y][k][0]));
                }
            }

看似很长,但仔细想想都是可以得到的.

然后就是码代码了.

using namespace std;
int i,k,x,y,t;
int n,m,d[100010];
int fa[100010],head[100010],tot;
bool flag[300010];
long long sum,ans;
int f[100010][20],g[100010][20][2];
int zui,ci;
inline long long min(long long a,long long b){
    return a>b?b:a;
}
inline long long max(long long a,long long b){
    return a>b?a:b;
}
struct edge{
    int  x,y,v;
    int next;
}o[300010],e[600010];
inline bool Orz(edge x,edge y){
    return x.v<y.v;
}
int get(int x){
    if(fa[x]==x)
        return x;
    return fa[x]=get(fa[x]);
}
inline void add(int x,int y,int v){
    tot++;
    e[tot].x=x;
    e[tot].y=y;
    e[tot].v=v;
    e[tot].next=head[x];
    head[x]=tot;
}
int main()
{
    n=read(),m=read();
    for(i=1;i<=m;i++)
        o[i].x=read(),o[i].y=read(),o[i].v=read();
    sort(o+1,o+1+m,Orz);
    for(i=1;i<=n;i++)
        fa[i]=i;
    for(i=1;i<=m;i++){
        x=get(o[i].x),y=get(o[i].y);
        if(x!=y){
            fa[x]=y;
            flag[i]=1;
            sum+=o[i].v;
            add(o[i].x,o[i].y,o[i].v);
            add(o[i].y,o[i].x,o[i].v);
            ans++;
            if(ans==n-1)
                break;
        }
    }
    ans=INF;
    queue<int> q;
    t=log2(n*1.0)+1;
    q.push(1);d[1]=1;
    while(q.size()){
        x=q.front();
        q.pop();
        for(i=head[x];i;i=e[i].next){
            y=e[i].y;
            if(d[y])continue;
            q.push(y);
            d[y]=d[x]+1;
            f[y][0]=x;
            g[y][0][0]=e[i].v;
            g[y][0][1]=-inf;
            for(k=1;k<=t;k++){
                f[y][k]=f[f[y][k-1]][k-1];
                g[y][k][0]=max(g[y][k-1][0],g[f[y][k-1]][k-1][0]);
                g[y][k][1]=max(g[y][k-1][1],g[f[y][k-1]][k-1][1]);
                if(g[y][k-1][0]!=g[f[y][k-1]][k-1][0])
                    g[y][k][1]=max(g[y][k][1],min(g[y][k-1][0],g[f[y][k-1]][k-1][0]));
            }
            
        }
    }
    for(i=1;i<=m;i++){
        if(!flag[i]){
            zui=ci=-inf;
            x=o[i].x,y=o[i].y;
            if(d[x]>d[y])swap(x,y);
            for(k=t;k>=0;k--)
                if(d[f[y][k]]>=d[x]){
                    zui=max(zui,g[y][k][0]);
                    y=f[y][k];
                }
            if(x!=y){
                for(k=t;k>=0;k--)
                    if(f[x][k]!=f[y][k]){
                        zui=max(zui,max(g[x][k][0],g[y][k][0]));
                        x=f[x][k],y=f[y][k];
                    }
                zui=max(zui,max(g[y][0][0],g[x][0][0]));
            }
            if(o[i].v>zui){
                ans=min(ans,sum-zui+o[i].v);
                continue;
            }
            x=o[i].x,y=o[i].y;
            if(d[x]>d[y])swap(x,y);
            for(k=t;k>=0;k--)
                if(d[f[y][k]]>=d[x]){
                    if(zui==g[y][k][0])
                        ci=max(ci,g[y][k][1]);
                    else
                        ci=max(ci,g[y][k][0]);
                }
            if(x!=y){
                for(k=t;k>=0;k--){
                    if(zui==max(g[x][k][0],g[y][k][0]))
                    {
                        if(g[x][k][0]==g[y][k][0])
                            ci=max(ci,max(g[y][k][1],g[x][k][1]));
                        if(g[x][k][0]>g[y][k][0])
                            ci=max(ci,max(g[x][k][1],g[y][k][0]));
                        if(g[x][k][0]<g[y][k][0])
                            ci=max(ci,max(g[x][k][0],g[y][k][1]));
                    }
                    else
                        ci=max(ci,max(g[x][k][0],g[y][k][0]));
                }
            }
            ans=min(ans,sum-ci+o[i].v);
        }
    }
    cout<<ans;
}

 全用int会wa,全用long long会MLE,结果最后查出来是赋值的锅...

转载于:https://www.cnblogs.com/qywyt/p/9804594.html

标题基于Python的自主学习系统后端设计与实现AI更换标题第1章引言介绍自主学习系统的研究背景、意义、现状以及本文的研究方法和创新点。1.1研究背景与意义阐述自主学习系统在教育技术领域的重要性和应用价值。1.2国内外研究现状分析国内外在自主学习系统后端技术方面的研究进展。1.3研究方法与创新点概述本文采用Python技术栈的设计方法和系统创新点。第2章相关理论与技术总结自主学习系统后端开发的相关理论和技术基础。2.1自主学习系统理论阐述自主学习系统的定义、特征和理论基础。2.2Python后端技术栈介绍DjangoFlask等Python后端框架及其适用场景。2.3数据库技术讨论关系型和非关系型数据库在系统中的应用方案。第3章系统设计与实现详细介绍自主学习系统后端的设计方案和实现过程。3.1系统架构设计提出基于微服务的系统架构设计方案。3.2核心模块设计详细说明用户管理、学习资源管理、进度跟踪等核心模块设计。3.3关键技术实现阐述个性化推荐算法、学习行为分析等关键技术的实现。第4章系统测试与评估对系统进行功能测试和性能评估。4.1测试环境与方法介绍测试环境配置和采用的测试方法。4.2功能测试结果展示各功能模块的测试结果和问题修复情况。4.3性能评估分析分析系统在高并发等场景下的性能表现。第5章结论与展望总结研究成果并提出未来改进方向。5.1研究结论概括系统设计的主要成果和技术创新。5.2未来展望指出系统局限性并提出后续优化方向。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值