Overview
给定一个无向图,请编写一个程序实现以下两种操作:
(1)D x y,从原图中删除连接x和y顶点的边。
(2)Q x y,询问x和y顶点是否连通。
Analysis
这也是连通问题,考虑用并查集解决。
但是这是删除的问题耶,怎么办?
考虑将删除变为连通,能不能将所有操作给反过来,从最后一个操作开始处理。
当然是可以的。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long Lint;
const int N=161240*4;
const int MOD=100009;
int n,q;
int f[N];
char kind[N]; int cx[N],cy[N];
inline int read(void)
{
int s=0; char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()) s=s*10+c-'0';
return s;
}
int m;
int ed[N][2];
struct Hash
{
int u,v,nxt;
}h[N<<1];
int tt,hd[MOD];
int find(int i)
{
return f[i]==i?i:f[i]=find(f[i]);
}
inline void ins(int u,int v)
{
int key=((Lint)u*n+v)%MOD;
h[++tt].u=u;
h[tt].v=v;
h[tt].nxt=hd[key];
hd[key]=tt;
}
inline int del(int u,int v)
{
int key=((Lint)u*n+v)%MOD;
for (int k=hd[key];k;k=h[k].nxt) if (h[k].u==u&&h[k].v==v) return 1;
return 0;
}
void init(void)
{
n=read(),m=read();
for (int i=1;i<=n;i++) f[i]=i;
for (int i=1;i<=m;i++) ed[i][0]=read(),ed[i][1]=read();
q=read();
for (int i=1;i<=q;i++)
{
scanf("\n"),kind[i]=getchar();
cx[i]=read(),cy[i]=read();
if (kind[i]=='D') ins(cx[i],cy[i]),ins(cy[i],cx[i]);
}
for (int i=1;i<=m;i++)
if (!del(ed[i][0],ed[i][1]))
f[find(ed[i][0])]=find(ed[i][1]);
}
int res[N];
void work(void)
{
for (int i=q;i>=1;i--) kind[i]=='D'?f[find(cx[i])]=find(cy[i]):res[++res[0]]=find(cx[i])==find(cy[i]);
for (int i=res[0];i>0;i--) printf("%c\n",res[i]?'C':'D');
}
int main(void)
{
init();
work();
return 0;
}
Sumarize
多次操作的离线算法有以下2种:
①结合各种定序和存储方法,在遍历其他的时候顺便求解。
②得到最后一次的答案,反向推回来。