P5227 [AHOI2013] 连通图
P5227 [AHOI2013] 连通图
题目描述
给定一个无向连通图和若干个小集合,每个小集合包含一些边,对于每个集合,你需要确定将集合中的边删掉后改图是否保持联通。集合间的询问相互独立
定义一个图为联通的当且仅当对于任意的两个顶点,都存在一条路径连接它们
数据范围
保证不存在重边和自环。
Solution:
好神的线段树分治.
首先我们将询问想象成时间,那么我们对每条边都可以维护它在那些时间是在线的,那些时间是离线的。我们按时间维护一颗线段树,然后我们再将这些边挂到线段树上。在进入一个线段树区间
实现:
我们将询问想象成一个标记永久化的东西,这样我们能使得时间复杂度很优秀,在退出一个点时,将这个点下的标记全部从并查集中撤销,用栈来存储需要删除的东西。
至于可撤销并查集:
就是在合并两个集合的时候先记一下他们原来的状态
Code:
#include<bits/stdc++.h> const int N=2e5+5; using namespace std; int n,m,q,cnt; int ans[N],a[N],b[N]; int siz[N],dep[N],fa[N]; vector<int> tim[N]; int find(int x){return fa[x]==x ? x : find(fa[x]);} struct Merge{ int fx,fy,dep_fx,dep_fy,siz_fx,siz_fy; }st[N<<2]; struct Segment_Tree{ struct Tree{ int l,r; vector<int> V; }t[N<<2]; #define ls x<<1 #define rs x<<1|1 #define mid (t[x].l+t[x].r>>1) void build(int x,int l,int r) { t[x].l=l,t[x].r=r;t[x].V.clear(); if(l==r)return; build(ls,l,mid);build(rs,mid+1,r); } void upd(int x,int L,int R,int id) { if(L<=t[x].l&&t[x].r<=R){t[x].V.emplace_back(id);return;} if(L<=mid)upd(ls,L,R,id); if(mid<R) upd(rs,L,R,id); } void dfs(int x) { int tmp=cnt; for(auto id : t[x].V) { int u=find(a[id]),v=find(b[id]); if(u!=v) { if(dep[u]>dep[v])swap(u,v); st[++cnt]={u,v,dep[u],dep[v],siz[u],siz[v]}; dep[v]+=(dep[v]==dep[u]);siz[v]+=siz[u];fa[u]=v; } } if(t[x].l==t[x].r){ans[t[x].l]=(siz[find(1)]==n ? 1 : 0);} else {dfs(ls);dfs(rs);} while(cnt>tmp) { auto [x,y,dep_x,dep_y,siz_x,siz_y] = st[cnt];cnt--; dep[x]=dep_x,dep[y]=dep_y; siz[x]=siz_x,siz[y]=siz_y; fa[x]=x,fa[y]=y; } } }T; void work() { cin>>n>>m; for(int i=1;i<=n;i++)fa[i]=i,siz[i]=dep[i]=1; for(int i=1;i<=m;i++) { scanf("%d%d",&a[i],&b[i]); } cin>>q; T.build(1,1,q); for(int i=1,c;i<=q;i++) { scanf("%d",&c); for(int j=1,x;j<=c;j++) { scanf("%d",&x); tim[x].push_back(i); } } for(int u=1,last;u<=m;u++) { last=0;tim[u].push_back(q+1); for(auto now : tim[u]) { if(last+1<=now-1)T.upd(1,last+1,now-1,u);last=now; } } T.dfs(1); for(int i=1;i<=q;i++) { printf(ans[i] ? "Connected\n" : "Disconnected\n"); } } int main() { //freopen("P5227.in","r",stdin);freopen("P5227.out","w",stdout); work(); return 0; }