zoukankan      html  css  js  c++  java
  • 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);
    		}
    	}
    }
    
    
    
  • 相关阅读:
    io学习
    asp.net文件上传进度条研究
    asp.net页面中的Console.WriteLine结果如何查看
    谨慎跟随初始目的不被关联问题带偏
    android 按钮特效 波纹 Android button effects ripple
    安卓工作室 日志设置
    安卓工作室 文件浏览器 android studio File browser
    一个新的Android Studio 2.3.3可以在稳定的频道中使用。A new Android Studio 2.3.3 is available in the stable channel.
    新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial
    码云,git使用 教程-便签
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14521118.html
Copyright © 2011-2022 走看看