AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3562
[分析]
若把每一个原子看作一个节点,将化学键看作一条边,那么这个题目要求的“分子的个数”很容易就可以看出是求图中联通块的个数。
求联通块的个数,可以使用并查集。可如何求出每一步的联通块的个数呢?
可以知道,当连上一条边时,若此边连接的是两个不同的联通块,那么分子个数就会减一;当删去一条边时,若删去这条边后,它两边的边不连通了,则分子个数就会加一。
如何判断是否连通呢?可以使用dfs。可是若用裸dfs,则程序会超时。我们可以考虑用并查集将图中不会被删除的边进行缩点,这样就可以大大减少程序运行的时间。
#include <iostream> #include <cstring> #include <cstdio> using namespace std; struct Node{ int nxt,data; }; int head[5010]; Node node[400010]; int k[200001][3]; int can[5010][5010]; bool lkan[5100]; int qus[10001][3]; bool vis[5010]; int n,m,ans,cnt=1,tot=0; int fa[5010]; bool kan[5010][5010]; void add(int x,int y){ node[cnt].nxt=head[x];node[cnt].data=y;head[x]=cnt;cnt++; node[cnt].nxt=head[y];node[cnt].data=x;head[y]=cnt;cnt++; } inline int find(int x){ int tmp=x,nxt; while(tmp!=fa[tmp])tmp=fa[tmp]; while(x!=tmp){ nxt=fa[x]; fa[x]=tmp; x=nxt; } return tmp; } inline void merge(int x,int y){ int fx=find(x),fy=find(y); if(fx!=fy)fa[fx]=fy; } inline int in(){ int ans=0; char x=getchar(); while(x<'0'||x>'9')x=getchar(); while(x>='0'&&x<='9'){ans=ans*10+x-'0';x=getchar();} return ans; } bool dfs(int now,int r){ if(now==r)return true; for(int i=head[now];i;i=node[i].nxt){ if(!vis[node[i].data]&&can[node[i].data][now]){ vis[node[i].data]=true; if(node[i].data==r){ return true; } if(dfs(node[i].data,r))return true; } } return false; } int main(){ n=in();m=in(); for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=m;i++){ int x,y; x=in();y=in(); k[i][1]=x; k[i][2]=y; merge(x,y); } for(int i=1;i<=n;i++){ int x=find(i); if(!lkan[x]){ lkan[x]=true; ans++; } } int q; q=in(); for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=q;i++){ char c; scanf("%s",&c); if(c=='Q')qus[i][0]=-1; else if(c=='D'){ int x,y; x=in();y=in(); qus[i][0]=1;qus[i][1]=x;qus[i][2]=y; kan[x][y]=kan[y][x]=true; } else{ int x,y; x=in();y=in(); qus[i][0]=2;qus[i][1]=x;qus[i][2]=y; } } for(int i=1;i<=m;i++){ if(!kan[k[i][1]][k[i][2]]){ merge(k[i][1],k[i][2]); } } for(int i=1;i<=m;i++){ int fx=find(k[i][1]),fy=find(k[i][2]); can[fx][fy]++;can[fy][fx]++; if(can[fx][fy]==1) add(find(fx),find(fy)); } for(int i=1;i<=q;i++){ int x=qus[i][1],y=qus[i][2]; int fx=find(x),fy=find(y); if(qus[i][0]==-1)printf("%d\n",ans); else if(qus[i][0]==1){ can[fx][fy]--;can[fy][fx]--; memset(vis,0,sizeof vis); vis[fx]=true; if(!dfs(fx,fy)){ ans++; } } else{ if(fx==fy)continue; memset(vis,0,sizeof vis); vis[fx]=true; if(!dfs(fx,fy)){ ans--; } can[fx][fy]++;can[fy][fx]++; if(can[fx][fy]==1)add(fx,fy); } } return 0; }