首页 > 其他分享 >致敬传奇 Kruskal 重构树题硬控我三小时

致敬传奇 Kruskal 重构树题硬控我三小时

时间:2024-07-26 20:29:58浏览次数:10  
标签:硬控 vis int 树题 Kruskal fa void id dis

NOI2018 归程

  1. 存边的数组拿来干两件事,忘了清空了,其实最好开两个的
  2. dfs 没开 vis 导致不知道为什么出现的绕圈
  3. 倍增的 fa[i][j] 定义的时候前面是 \(2^{i}\) 写着写着记错成后面了
  4. 忘记要递减排序了,跑的最小生成树
  5. 并查集没初始化
  6. 不知道为什么,倍增的 fa 数组单独一块处理会 WA,回来发现是因为只循环到 n,没处理虚点,不过这个时候我已经把它塞到 dfs 里对了
  7. 忘记删输出中间变量
  8. 忘记删 freopen
  9. 并查集忘记路径压缩

因为破防了,特此记录

#include<bits/stdc++.h>
using namespace std;
const int N=800001;
int n,m;
struct edge{
	int to,w;
};
vector<edge>e[N];
struct aedge{
	int x,y,l;
	bool operator <(const aedge &A)const{
		return l>A.l;
	}
}E[N];
struct node{
	int id,w;
	bool operator <(const node &A)const{
		return w>A.w;
	}
};
int fa[N][21],mn[N],val[N];
namespace dsu{
	int fa[N];
	void clear(int n){
		for(int i=1;i<=n;++i){
			fa[i]=i;
		}
	}
	int find(int id){
//		cout<<"find "<<id<<endl;
		if(id==fa[id]) return id;
		fa[id]=find(fa[id]);
		return fa[id];
	}
}
namespace DIJKSTRA{
	int vis[N],dis[N];
	priority_queue<node>q;
	void dij(){
		memset(vis,0,sizeof vis);
		memset(dis,0x3f,sizeof dis);
		vis[1]=1;dis[1]=0;
		q.push({1,dis[1]});
		while(!q.empty()){
			node u=q.top();q.pop();
			for(edge i:e[u.id]){
				if(dis[i.to]>dis[u.id]+i.w){
					dis[i.to]=dis[u.id]+i.w;
					q.push({i.to,dis[i.to]});
				}
			}
		}
	}
}
bool vvis[N];
void dfs(int now,int last){
	if(vvis[now]) return;
	vvis[now]=true;
//	cout<<"dfs "<<now<<" "<<last<<endl;
//	cout<<"dfs "<<now<<" "<<last<<endl;
	fa[now][0]=last;
	mn[now]=DIJKSTRA::dis[now];
//	cout<<now<<" "<<mn[now]<<endl;
	for(int i=1;i<=20;++i){
		fa[now][i]=fa[fa[now][i-1]][i-1];
	}
	for(edge i:e[now]){
		if(i.to!=last){
			dfs(i.to,now);
			mn[now]=min(mn[now],mn[i.to]);
		}
	}
}
int cnt;
int main(){
//	freopen("in.in","r",stdin);
//	freopen("1.out","w",stdout); 
	int cases;scanf("%d",&cases);while(cases--){
		scanf("%d %d",&n,&m);
		memset(mn,0,sizeof mn);
		memset(fa,0,sizeof fa);
		for(int i=1;i<=N;++i){
			e[i].clear();
		}
		for(int i=1;i<=m;++i){
			int x,y,l,a;scanf("%d %d %d %d",&x,&y,&l,&a);
			E[i]={x,y,a};
			e[x].push_back({y,l});
			e[y].push_back({x,l});
//			cout<<"add "<<x<<" "<<y<<endl;
//			cout<<"add "<<y<<" "<<x<<endl;
		}
//		cout<<"aa "<<endl;
		DIJKSTRA::dij();
//		cout<<"aa "<<endl;
		sort(E+1,E+m+1);
//		cout<<"aa "<<endl;
		dsu::clear(N);
		for(int i=1;i<=N;++i){
			e[i].clear();
		}
//		cout<<"aa "<<endl;
		int now=n;
		for(int i=1;i<=m;++i){
//			cout<<"aa "<<i<<endl;
//			cout<<E[i].x<<" "<<E[i].y<<endl;
			int x=E[i].x,y=E[i].y,w=E[i].l;
			int fx=dsu::find(x);
//			cout<<"fx"<<endl;
			int fy=dsu::find(y);
//			cout<<"fy"<<endl;
			if(fx^fy){
				val[++now]=w;
//				cout<<"你他妈到底在哪RE了"<<endl;
				dsu::fa[fx]=dsu::fa[fy]=dsu::fa[now]=now;
//				cout<<"6"<<endl;
				e[now].push_back({fx,1});
//				cout<<"6"<<endl;
				e[now].push_back({fy,1});
//				cout<<"add "<<now<<" "<<fx<<endl;
//				cout<<"add "<<now<<" "<<fy<<endl;
//				cout<<"6"<<endl;
			}
		}
//		cout<<"dfs"<<endl;
		memset(vvis,false,sizeof vvis);
		dfs(now,0);
		int last=0;
//		cout<<"54"<<endl;
		int q,k,s;scanf("%d %d %d",&q,&k,&s);
		for(int i=1;i<=q;++i){
			int x,y,v,p;
			scanf("%d %d",&x,&y);
			v=(x+k*last-1)%n+1;
			p=(y+k*last)%(s+1);
			for(int j=20;j>=0;--j){
				if(fa[v][j] and val[fa[v][j]]>p) v=fa[v][j];
			}
//			cout<<"find "<<v<<endl;
			printf("%d\n",last=mn[v]);
		}
	}
}

标签:硬控,vis,int,树题,Kruskal,fa,void,id,dis
From: https://www.cnblogs.com/HaneDaCafe/p/18326182

相关文章

  • kruskal重构树
    比较好理解,相当于重建了一个二叉树,所有的父亲节点都为原来图中的边,儿子节点为点。重构树就可以利用lca求两点间的最大(或者最小)边权以及一些树上操作。较为简单的应用,需要用线段树来维护信息。点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintN=1e6;i......
  • Kruskal 重构树学习笔记
    Kruskal想必大家都不陌生,这是一种求最小生成树的算法。关于Kruskal重构树,就是把一张图转化为一个堆。具体来说,我们可以处理出来从\(u\)到\(v\)路径中的点权或边权的极值。比如上面这张图(前为编号,[]内为点权),我们可以将它重构为小顶堆,如下请注意,这棵树有着严格的方向,......
  • 最小生成树(Kruskal和Prim算法)
    最小生成树(Kruskal和Prim算法)部分资料来源于:最小生成树(Kruskal算法)_kruskal算法求最小生成树-CSDN博客、【算法】最小生成树——Prim和Kruskal算法-CSDN博客关于图的几个概念定义:连通图:在无向图中,若任意两个顶点vi与vj都有路径相通,则称该无向图为连通图。强连通图:在有向......
  • 代码随想录算法训练营第六十三天 | prim算法、kruskal算法、复习
    53.寻宝—prim算法题目链接:https://kamacoder.com/problempage.php?pid=1053文档讲解:https://programmercarl.com/kamacoder/0053.%E5%AF%BB%E5%AE%9D-prim.html思路本题是最小生成树的模板题,最小生成树可以使用prim算法,也可以使用kruskal算法计算出来。prim算......
  • 【数据结构与算法】最小生成树,Prim算法,Kruskal算法 详解
    最小生成树的实际应用背景。最节省经费的前提下,在n个城市之间建立通信联络网。Kruskal算法(基于并查集)voidinit(){for(inti=1;i<=n;i++){pre[i]=i;}}llroot(lla){lli=a;while(pre[i]!=i){i=pre[i];......
  • 算法课程笔记——Kruskal & Prim
    算法课程笔记——Kruskal&Prim......
  • 数树题
    数树题。[ARC155F]DirectableasDesired给定长度为\(N\)的非负整数序列\(D=(D_1,D_2,\dots,D_N)\),满足\(\sum_{i=1}^ND_i=N-1\)。统计有多少带标号无根树,节点编号\(1\simN\),满足以下条件:存在一种将\(N-1\)条边分别定向的方案,使得节点\(i\)的出度为\(D_i\)。......
  • C语言Kruskal算法求最小生成树
    Kruskal算法求出最小生成树。图形算法描述先找最小权值边为1的边有(V1,V4),(V2,V9),保证不产生回路就可以成功选择边除去上一次找的边后,在找权值最小的边为2的有(V2,V3),(V4,V3),(V5,V6),(V9,V8),连接不产生回路的边除去之前找过的边,后面再看权值最小的边为3的边有(V1,V3),(V7,V8),(V9,V7)按顺......
  • Kruskal最小生成树
    Kruskal最小生成树Kruskal最小生成树是求解图G的最小生成树(最优树)T的算法。Kruskal算法是基于边来构造的算法,相对好理解。还有一个Prim算法是从点方面考虑的构建方式。对于图\(G(V,E)\),Kruskal算法的时间复杂度是\(O(|E|\cdot\alpha(V))\),其中α为Ackermann函数,其增长非......
  • Kruskal 算法实现最小生成树
    1.算法思想将整个图的所有边和权值拿出来,放进一个列表中,再将按权值大小从小到大排列,每次取出权值最小的边放回图中,并在每次放进图的过程中判断放进这个边有没有形成环(形成环的话就不能放进该边),再将当前数的权值相加,求得最小权值。 Kruskal算法是一种用于在加权图中找到最......