如今有n个点,m条编号为1-m的无向边,给出k个询问,每一个询问给出区间[l,r],让输出删除标号为l-r的边后还有几个连通块?c++
去除编号为[l,r]的边后,只剩下了[1,l-1]&&[r+1,m]两部分。spa
咱们维护一个前缀以及后缀并查集,询问的时候把这两部分的边合并一下,就能够求出连通块的个数。code
精辟!component
#include<bits/stdc++.h> #include<vector> #include<stdio.h> #include<algorithm> #include<string.h> #include<string> #include<math.h> #include<queue> #include<map> #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; const int N=1e4+10; const int mod=1e9+7; const int inf=0x3f3f3f3f; int n,m,k; struct dsu { int fa[510],num; void init() { num=n; for(int i=1;i<=n;i++) fa[i]=i; } int find(int x) { if(fa[x]==x) return x; return fa[x]=find(fa[x]); } void join(int u,int v) { u=find(u); v=find(v); if(u==v) return; fa[u]=v; num--; } }pre[N],suf[N]; struct note { int u,v; }arr[N]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&arr[i].u,&arr[i].v); pre[0].init(); for(int i=1;i<=m;i++) { pre[i]=pre[i-1]; pre[i].join(arr[i].u,arr[i].v); } suf[m+1].init(); for(int i=m;i>=0;i--) { suf[i]=suf[i+1]; suf[i].join(arr[i].u,arr[i].v); } scanf("%d",&k); while(k--) { int l,r; scanf("%d%d",&l,&r); dsu tmp=pre[l-1]; for(int i=1;i<=n;i++)//把同一个点在两部分中的祖先合并 tmp.join(tmp.find(i),suf[r+1].find(i)); printf("%d\n",tmp.num); } return 0; } /* */
博客get