动态最小生成树 题解(线段树+归并排序)
动态最小生成树
https://ac.nowcoder.com/acm/contest/9986/H
题目链接
题目思路
看到单点修改,区间查询其实很容易想到线段树
但是这个线段树有点特殊
线段树的每个节点代表这个区间的最小生成树的所有边,用vector存
那么每个节点最多n-1条边
你每次合并使用类似归并排序就是
如果暴力合并就是
那么使用归并排序总的时间复杂度就是
代码
#include<bits/stdc++.h> #define fi first #define se second #define debug cout<<"I AM HERE"<<endl; using namespace std; typedef long long ll; const int maxn=3e4+5,inf=0x3f3f3f3f,mod=1e9+7; const int eps=1e-6; int n,m,q; int fa[maxn]; struct edge{ int u,v,w; }e[maxn]; vector<edge> tree[maxn<<2]; bool cmp(edge a,edge b){ return a.w<b.w; } int findd(int x){ return x==fa[x]?x:fa[x]=findd(fa[x]); } vector<edge> mer(vector<edge> a,vector<edge> b){ vector<edge> ans; for(int i=1;i<=n;i++){ fa[i]=i; } a.push_back({-1,-1,inf}); b.push_back({-1,-1,inf}); int id1=0,id2=0; while(id1<((int)a.size()-1)||id2<((int)b.size()-1)){ int x,y; if(a[id1].w<=b[id2].w){ x=findd(a[id1].u); y=findd(a[id1].v); id1++; if(x==y) continue; fa[x]=y; ans.push_back(a[id1-1]); }else{ x=findd(b[id2].u); y=findd(b[id2].v); id2++; if(x==y) continue; fa[x]=y; ans.push_back(b[id2-1]); } } return ans; } void build(int node,int l,int r){ if(l==r){ tree[node].push_back(e[l]); return ; } int mid=(l+r)/2; build(node<<1,l,mid); build(node<<1|1,mid+1,r); tree[node]=mer(tree[node<<1],tree[node<<1|1]); } void update(int node,int l,int r,int pos){ if(l==r){ tree[node][0]=e[pos]; return ; } int mid=(l+r)>>1; if(mid>=pos) update(node<<1,l,mid,pos); else update(node<<1|1,mid+1,r,pos); tree[node]=mer(tree[node<<1],tree[node<<1|1]); } vector<edge> query(int node,int l,int r,int L,int R){ if(L<=l&&r<=R){ return tree[node]; } int mid=(l+r)/2; vector<edge> ans; if(mid>=L) ans=mer(ans,query(node<<1,l,mid,L,R)); if(mid<R) ans=mer(ans,query(node<<1|1,mid+1,r,L,R)); return ans; } signed main(){ scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=m;i++){ scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); } build(1,1,m); for(int i=1,x,y,z,t,l,r,opt;i<=q;i++){ scanf("%d",&opt); if(opt==1){ scanf("%d%d%d%d",&x,&y,&z,&t); e[x]={y,z,t}; update(1,1,m,x); }else{ scanf("%d%d",&l,&r); vector<edge> ans=query(1,1,m,l,r); int sum=0; for(int i=0;i<ans.size();i++){ sum+=ans[i].w; } if(ans.size()!=n-1){ printf("Impossible\n"); }else{ printf("%d\n",sum); } } } return 0; }