[BZOJ 4668]冷战(带边权并查集+启发式合并)
[BZOJ 4668]冷战(并查集+启发式合并)
题面
一开始有n个点,动态加边,同时查询u,v最早什么时候联通。强制在线
分析
用并查集维护连通性,每个点x还要另外记录tim[x],表示x什么时间与父亲相连。查询u,v的时候显然可以看出,答案就是u到v路径上的点tim的最大值。所以像求lca一样暴力向上跳就可以了。然后按秩合并,树高是O(logn)的,所以每次查询是O(logn)的
代码
#include<iostream> #include<cstdio> #include<cstring> #define maxn 500000 using namespace std; int n,m; struct disjoint_set{ int fa[maxn+5]; int tim[maxn+5];//记录x什么时间与父亲相连 int sz[maxn+5]; int find(int x){ while(fa[x]!=0) x=fa[x]; return x; } int get_deep(int x){ int ans=0; while(fa[x]!=0){ ans++; x=fa[x]; } return ans; } void merge(int x,int y,int t){ int fx=find(x),fy=find(y); if(fx!=fy){ if(sz[fx]>sz[fy]) swap(fx,fy); fa[fx]=fy; tim[fx]=t; sz[fy]+=sz[fx]; } } int query(int x,int y){//其实是跳到lca int ans=0; if(find(x)==find(y)){ int dx=get_deep(x),dy=get_deep(y); if(dx<dy){ swap(x,y); swap(dx,dy); } while(dx>dy){ ans=max(ans,tim[x]); x=fa[x]; dx--; } if(x==y) return ans; while(x!=y){ ans=max(ans,max(tim[x],tim[y])); x=fa[x]; y=fa[y]; } return ans; }else return 0; } void ini(int n){ for(int i=1;i<=n;i++){ fa[i]=0; sz[i]=1; } } }S; int main(){ int u,v,cmd; int last=0; scanf("%d %d",&n,&m); int tim=0; S.ini(n); for(int i=1;i<=m;i++){ scanf("%d %d %d",&cmd,&u,&v); u^=last; v^=last; if(cmd==0) S.merge(u,v,++tim); else{ last=S.query(u,v); printf("%d\n",last); } } } /* 5 9 0 2 5 1 2 5 */
版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具