• Nowcoder9986H.动态最小生成树(线段树+Krustral算法+归并排序)


    牛客暑期集训第六场题解

    zhanglichen

    H.动态最小生成树

    题意:

    小Z喜欢最小生成树。

    小Z有一张n*m的图,请你支持两种操作:

    (1)修改第x条边为连接点y,z,边权为t。

    (2)查询只用编号在[l,r]范围内的边,得到的最小生成树权值是多少。

    题解:

    猜想一个性质:

    对于两个边集A和B,这两个边集合并后的边集C的最小生成树可以直接由A的最小生成树和B的最小生成树合并得到(我不会证)。

    观察到点数只有200,考虑用线段树维护,线段树上每个节点维护对应区间内的边集涉及的点集的最小生成树。

    线段树pushup的时候,不用排序,定义两个指针x和y分别表示左区间的遍历位置和右区间的遍历位置,采用有序链表合并的方式合并两个区间。

    注意:father数组一定要定义在外面,因为程序在同一时间只能运行一层递归函数,只需要每次合并区间的时候初始化一下father[i]即可,如果每个节点都定义一个father数组,会导致超时。

    时间复杂度(O(200nlogn))

    // Problem: 动态最小生成树
    // Contest: NowCoder
    // URL: https://ac.nowcoder.com/acm/contest/9986/H
    // Memory Limit: 1048576 MB
    // Time Limit: 10000 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    //200个点,30000条边
    //30000个询问
    //对边分块
    //每一块的边所包含的点集的最小生成树
    //合并点集
    //枚举两块边的每条生成树上的边
    //取小的边作为新的生成树
    
    //单点修改
    
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3e4+100;
    int n,m,q;
    
    
    
    struct edge {
    	int u,v,w;
    	bool operator < (const edge &r) const {
    		return w<r.w;
    	}
    }e[maxn];
    int father[205];
    
    struct node {
    	int l,r;
    	vector<int> p;
    	long long sum=0;
    }segTree[maxn<<2];
    
    
    int findfather (int x) {
    	int a=x;
    	while (x!=father[x]) x=father[x];
    	while (a!=father[a]) {
    		int z=a;
    		a=father[a];
    		father[z]=x;
    	}
    	return x;
    }
    
    void build (int i,int l,int r) {
    	segTree[i].l=l;
    	segTree[i].r=r;
    	if (l==r) {
    		segTree[i].p.push_back(l);
    		segTree[i].sum=e[l].w;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(i<<1,l,mid);
    	build(i<<1|1,mid+1,r);
    	
    	for (int j=1;j<=n;j++)father[j]=j;segTree[i].sum=0;segTree[i].p.clear();
    	int x=0,y=0;
    	while (x<segTree[i<<1].p.size()||y<segTree[i<<1|1].p.size()) {
    		if (x<segTree[i<<1].p.size()&&y<segTree[i<<1|1].p.size()) {
    			if (e[segTree[i<<1].p[x]].w<e[segTree[i<<1|1].p[y]].w) {
    				int u=findfather(e[segTree[i<<1].p[x]].u);
    				int v=findfather(e[segTree[i<<1].p[x]].v);
    				if (u==v) {
    					x++;
    					continue;
    				}
    				segTree[i].p.push_back(segTree[i<<1].p[x]);
    				father[u]=v;
    				segTree[i].sum+=e[segTree[i<<1].p[x]].w;
    				x++;
    			} 
    			else {
    				int u=findfather(e[segTree[i<<1|1].p[y]].u);
    				int v=findfather(e[segTree[i<<1|1].p[y]].v);
    				if (u==v) {
    					y++;
    					continue;
    				}
    				segTree[i].p.push_back(segTree[i<<1|1].p[y]);
    				father[u]=v;
    				segTree[i].sum+=e[segTree[i<<1|1].p[y]].w;
    				y++;
    			}
    		}
    		else if (x<segTree[i<<1].p.size()) {
    			int u=findfather(e[segTree[i<<1].p[x]].u);
    				int v=findfather(e[segTree[i<<1].p[x]].v);
    				if (u==v) {
    					x++;
    					continue;
    				}
    				segTree[i].p.push_back(segTree[i<<1].p[x]);
    				father[u]=v;
    				segTree[i].sum+=e[segTree[i<<1].p[x]].w;
    				x++;
    		}
    		else {
    			int u=findfather(e[segTree[i<<1|1].p[y]].u);
    				int v=findfather(e[segTree[i<<1|1].p[y]].v);
    				if (u==v) {
    					y++;
    					continue;
    				}
    				segTree[i].p.push_back(segTree[i<<1|1].p[y]);
    				father[u]=v;
    				segTree[i].sum+=e[segTree[i<<1|1].p[y]].w;
    				y++;
    		}
    	}
    }
    void up (int i,int pp) {
    	if (segTree[i].l==pp&&segTree[i].r==pp) {
    		return;
    	}
    	int mid=(segTree[i].l+segTree[i].r)>>1;
    	if (pp<=mid) up(i<<1,pp);
    	if (pp>mid) up(i<<1|1,pp);
    	
    	for (int j=1;j<=n;j++)father[j]=j;segTree[i].sum=0;segTree[i].p.clear();
    	int x=0,y=0;
    	while (x<segTree[i<<1].p.size()||y<segTree[i<<1|1].p.size()) {
    		if (x<segTree[i<<1].p.size()&&y<segTree[i<<1|1].p.size()) {
    			if (e[segTree[i<<1].p[x]].w<e[segTree[i<<1|1].p[y]].w) {
    				int u=findfather(e[segTree[i<<1].p[x]].u);
    				int v=findfather(e[segTree[i<<1].p[x]].v);
    				if (u==v) {
    					x++;
    					continue;
    				}
    				segTree[i].p.push_back(segTree[i<<1].p[x]);
    				father[u]=v;
    				segTree[i].sum+=e[segTree[i<<1].p[x]].w;
    				x++;
    			} 
    			else {
    				int u=findfather(e[segTree[i<<1|1].p[y]].u);
    				int v=findfather(e[segTree[i<<1|1].p[y]].v);
    				if (u==v) {
    					y++;
    					continue;
    				}
    				segTree[i].p.push_back(segTree[i<<1|1].p[y]);
    				father[u]=v;
    				segTree[i].sum+=e[segTree[i<<1|1].p[y]].w;
    				y++;
    			}
    		}
    		else if (x<segTree[i<<1].p.size()) {
    			int u=findfather(e[segTree[i<<1].p[x]].u);
    				int v=findfather(e[segTree[i<<1].p[x]].v);
    				if (u==v) {
    					x++;
    					continue;
    				}
    				segTree[i].p.push_back(segTree[i<<1].p[x]);
    				father[u]=v;
    				segTree[i].sum+=e[segTree[i<<1].p[x]].w;
    				x++;
    		}
    		else {
    			int u=findfather(e[segTree[i<<1|1].p[y]].u);
    				int v=findfather(e[segTree[i<<1|1].p[y]].v);
    				if (u==v) {
    					y++;
    					continue;
    				}
    				segTree[i].p.push_back(segTree[i<<1|1].p[y]);
    				father[u]=v;
    				segTree[i].sum+=e[segTree[i<<1|1].p[y]].w;
    				y++;
    		}
    	}
    }
    
    node query (int i,int l,int r) {
    	if (segTree[i].l>=l&&segTree[i].r<=r) {
    		return segTree[i];
    	}
    	int mid=(segTree[i].l+segTree[i].r)>>1;
    	vector<edge> pp;
    	node ans;
    	node t1;
    	node t2;
    	int x=0,y=0;
    	if (l<=mid) t1=query(i<<1,l,r);
    	if (r>mid) t2=query(i<<1|1,l,r);
    	for (int j=1;j<=n;j++) father[j]=j;
    	ans.sum=0;
    	while (x<t1.p.size()||y<t2.p.size()) {
    		if (x<t1.p.size()&&y<t2.p.size()) {
    			if (e[t1.p[x]].w<e[t2.p[y]].w) {
    				int u=findfather(e[t1.p[x]].u);
    				int v=findfather(e[t1.p[x]].v);
    				if (u==v) {
    					x++;
    					continue;
    				}
    				ans.p.push_back(t1.p[x]);
    				father[u]=v;
    				ans.sum+=e[t1.p[x]].w;
    				x++;
    			} 
    			else {
    				int u=findfather(e[t2.p[y]].u);
    				int v=findfather(e[t2.p[y]].v);
    				if (u==v) {
    					y++;
    					continue;
    				}
    				ans.p.push_back(t2.p[y]);
    				father[u]=v;
    				ans.sum+=e[t2.p[y]].w;
    				y++;
    			}
    		}
    		else if (x<t1.p.size()) {
    			int u=findfather(e[t1.p[x]].u);
    				int v=findfather(e[t1.p[x]].v);
    				if (u==v) {
    					x++;
    					continue;
    				}
    				ans.p.push_back(t1.p[x]);
    				father[u]=v;
    				ans.sum+=e[t1.p[x]].w;
    				x++;
    		}
    		else {
    			int u=findfather(e[t2.p[y]].u);
    				int v=findfather(e[t2.p[y]].v);
    				if (u==v) {
    					y++;
    					continue;
    				}
    				ans.p.push_back(t2.p[y]);
    				father[u]=v;
    				ans.sum+=e[t2.p[y]].w;
    				y++;
    		}
    	}
    	return ans;
    }
    int 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);
    	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].u=y;e[x].v=z;e[x].w=t;
    			up(1,x);
    		}
    		else {
    			int l,r;
    			scanf("%d%d",&l,&r);
    			node ans=query(1,l,r);
    			int f=1;
    			for (int i=1;i<=n;i++) if (findfather(i)!=findfather(1)) f=0;
    			if (!f) {
    				printf("Impossible
    ");
    				continue;
    			}
    			printf("%lld
    ",ans.sum);
    		}
    	}
    }
    
    
    
  • 相关阅读:
    20、Python之函数参数的使用
    19、Python之函数的基本使用
    18、Python之文件修改及f.seek的使用
    17、Python之文件处理的其他方法
    15、字符编码
    14、Python基本数据类型及内置方法(集合)
    13、Python基本数据类型及内置方法(列表、元组、字典)
    12、Python基本数据类型及内置方法(数字、字符串)
    11、Python流程控制之for循环
    10、Python流程控制之while循环
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14521118.html
Copyright © 2020-2023  润新知