动态最小生成树

题目详情

在这里插入图片描述

题目解析

动态最小生成树用线段树维护,线段树维护的区间的是所有的边,线段树的点维护一个数组,代表这一段边的区间组成的最小生成树用到了哪些边的编号,合并的过程类似归并排序,在两段的最小生成树边中挑,构造出新的最小生成树,记录所使用的边

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=210,M=30010;
struct Edge
{
    int a,b,c;
}e[M];
struct Node
{
    int id[N];
}tr[M*8];
int p[N];
int ans[N],tmp[N];
int n,m,q;
int find(int x)
{
    if(x!=p[x])return find(p[x]);
    return p[x];
}
void pushup(int root)
{
    for(int i=1;i<=n;i++)p[i]=i,tr[root].id[i]=0;
    int l=root*2,r=root*2+1;
    int pp=1,qq=1;
    for(int i=1;i<n;)
    {
        int pos1=tr[l].id[pp],pos2=tr[r].id[qq];
        if(!pos1&&!pos2)break;
        if(!pos1||(pos2&&e[pos1].c>=e[pos2].c))
        {
            int a=find(e[pos2].a);
            int b=find(e[pos2].b);
            if(a!=b)
            {
                tr[root].id[i]=pos2;
                p[a]=b;
                i++;
            }
            qq++;
        }
        else
        {
            int a=find(e[pos1].a);
            int b=find(e[pos1].b);
            if(a!=b)
            {
                tr[root].id[i]=pos1;
                p[a]=b;
                i++;
            }
            pp++;
        }
    }
}
void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u].id[1]=l;
        return ;
    }
    int mid=l+r>>1;
    build(u*2,l,mid);
    build(u*2+1,mid+1,r);
    pushup(u);
}
void update(int u,int l,int r,int x)
{
    if(l==r)return;
    int mid=l+r>>1;
    if(x<=mid)update(u*2,l,mid,x);
    else update(u*2+1,mid+1,r,x);
    pushup(u);
}
void solve(int root)
{
    for(int i=1;i<=n;i++)p[i]=i,tmp[i]=0;
    int pp=1,qq=1;
    for(int i=1;i<n;)
    {
        int pos1=tr[root].id[pp];
        int pos2=ans[qq];
        if(!pos1&&!pos2)break;
        if(!pos1||(pos2&&e[pos1].c>=e[pos2].c))
        {
            int a=find(e[pos2].a);
            int b=find(e[pos2].b);
            if(a!=b)
            {
                tmp[i]=pos2;
                p[a]=b;
                i++;
            }
            qq++;
        }
        else
        {
            int a=find(e[pos1].a);
            int b=find(e[pos1].b);
            if(a!=b)
            {
                tmp[i]=pos1;
                p[a]=b;
                i++;
            }
            pp++;
        }
    }
    for(int i=1;i<=n;i++)ans[i]=tmp[i];
}
void query(int u,int l,int r,int L,int R)
{
    if(l>=L&&r<=R)
    {
        solve(u);
        return ;
    }
    int mid=l+r>>1;
    if(L<=mid)query(u*2,l,mid,L,R);
    if(R>mid)query(u*2+1,mid+1,r,L,R);
}
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
    }
    build(1,1,m);
    while(q--)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            int x,y,z,t;
            scanf("%d%d%d%d",&x,&y,&z,&t);
            e[x].a=y,e[x].b=z,e[x].c=t;
            update(1,1,m,x);
        }
        else 
        {
            memset(ans,0,sizeof(ans));
            int l,r;
            scanf("%d%d",&l,&r);
            query(1,1,m,l,r);
            if(!ans[n-1])puts("Impossible");
            else
            {
            ll res=0;
            for(int i=1;i<=n;i++)res+=e[ans[i]].c;
            cout<<res<<endl;
            }
        }
    }
    return 0;
}
### VC++6.0 中实现动态最小生成树算法 #### 动态最小生成树简介 动态最小生成树(Dynamic Minimum Spanning Tree, DMST)是指在一个图结构中,随着边权重的变化或其他操作(如增加或删除节点/边),能够实时更新其最小生成树的一种数据结构和技术。对于这类问题,在VC++6.0环境下可以通过Prim或Kruskal算法为基础进行扩展处理[^1]。 #### Prim算法的改进版用于DMST 为了适应动态变化的需求,可以在经典Prim算法基础上加入增量式维护机制: ```cpp #include <vector> #include <queue> using namespace std; struct Edge { int u, v; double w; }; class DynamicMST_Prim { private: vector<vector<Edge>> adjList; // 邻接表表示加权无向图 priority_queue<pair<double,int>, vector<pair<double,int>>, greater<>> pq; public: void addEdge(int from, int to, double weight); void removeEdge(int from, int to); // 支持删除边的操作 void updateWeight(int from, int to, double newWeight); // 更新特定边的权重 double getMinimumSpanningTreeCost(); }; ``` 此代码片段展示了基于优先队列优化后的Prim算法框架,并增加了`removeEdge()`和`updateWeight()`方法以便于应对图形拓扑结构调整带来的影响[^3]。 #### Kruskal算法的改进版本适用于DMST场景 同样地,也可以考虑采用并查集(Union-Find Set)配合贪心策略来构建支持快速查询连通性和路径压缩特性的动态最小生成树解决方案: ```cpp #include <algorithm> const int MAXN = 1e5 + 7; int parent[MAXN], rank_[MAXN]; void initDSU(int n){ iota(parent,parent+n,0); fill(rank_,rank_+n,0); } // 并查集相关函数省略... double dynamic_kruskal(vector<Edge>& edges, bool* updatedEdges){ sort(edges.begin(),edges.end(),[](auto &a, auto &b){return a.w<b.w;}); double mst_cost=0.; for(auto &[u,v,w]:edges){ if(updatedEdges[u]){ continue; } if(find(u)!=find(v)){ unionSet(u,v); mst_cost+=w; } } return mst_cost; } ``` 上述C++程序实现了带有标记数组`updatedEdges[]`控制哪些边参与当前轮次计算逻辑下的Kruskal算法变体形式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值