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;
}