CF1706E 题解
题目大意
给定一个 个点 条边的无向图,询问 次,每次询问会指定两个正整数 ,问要使对于 的所有 均有路径可以互相到达,最少需要加入前多少条边。
思路
考虑到每一次询问实质上就是问你在按顺序加了多少条边之后,编号 之间的点都在同一个联通块中。
记 表示 和 在加了 条边之后处在同一个联通块,那么每一次询问的答案就是 。
在求解出所有的 之后就可以直接用 ST 表或者线段树解决区间查询。
那么现在问题在于怎么求解 。
考虑顺序加边用启发式合并的思想处理 ,具体操作流程如下:
- 当前要合并 所在的集合 。
- 如果 ,那么遍历 中的每一个元素 ,处理 和 。
- 否则交换 再操作即可。
不难看出每一个点在启发式合并的过程中最多被合并 次,而并查集复杂度为 ,所以处理 的这一部分复杂度为 。
总时间复杂度 ,可以通过本题。
#include<bits/stdc++.h> #define RI register int #define ll long long #define ull unsigned long long #define YES puts("YES") #define NO puts("NO") using namespace std; namespace IO{ inline int read(){ RI X=0, W=0;register char ch=getchar(); while(!isdigit(ch)) W|=ch=='-', ch=getchar(); while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48), ch=getchar(); return W?-X:X; } inline void write(int x){ if(x<0) x=-x, putchar('-'); if(x>9) write(x/10); putchar(x%10+'0'); } }using namespace IO; const int MAXN = 2e5+5; int n, m, q; int fa[MAXN]; int tree[MAXN << 2], minn[MAXN]; int siz[MAXN]; vector<int> G[MAXN]; inline int find(int x){ if(fa[x]==x) return x; return fa[x]=find(fa[x]); } inline void build(int p, int l, int r){ if(l==r){ tree[p]=minn[l]; return ; } int mid=(l+r)>>1; build(p<<1,l,mid), build(p<<1|1,mid+1,r); tree[p]=max(tree[p<<1],tree[p<<1|1]); } inline int ask(int p, int l, int r, int L, int R){ if(L>R) return 0; if(L<=l && r<=R) return tree[p]; int mid=(l+r)>>1, res=0; if(L<=mid) res=ask(p<<1,l,mid,L,R); if(R>mid) res=max(res,ask(p<<1|1,mid+1,r,L,R)); return res; } inline void solve(){ //4 [space] n=read(),m=read(),q=read();int p;fa[n+1]=n+1; for(int i=1;i<=n;++i) G[i].clear(), G[i].push_back(i), fa[i]=i, siz[i]=1, minn[i]=1e9; for(int i=1;i<=m;++i) { int x, y; x=read(), y=read(); x=find(x), y=find(y); if(x==y) continue; if(siz[x]>siz[y]) swap(x,y); siz[y]+=siz[x];fa[x]=y; for(int A=0;A<G[x].size();++A){ p=G[x][A]; if(find(p)==find(p+1)) minn[p]=min(i,minn[p]); if(find(p)==find(p-1)) minn[p-1]=min(minn[p-1],i); G[y].push_back(p); } G[x].clear();siz[x]=0; } build(1,1,n-1); while(q--){ int l, r; l=read(), r=read(); write(ask(1,1,n-1,l,r-1)), putchar(32); } putchar(10); } int main(){ int t=read(); while(t--) solve(); return 0; }
最后附上 评测记录。
本文作者:OI 生活
本文链接:https://www.cnblogs.com/OccasionalDreamer/p/18012074
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步