您的位置:首页 > 其它

【NOIP模拟题】连通

2016-01-29 10:57 351 查看

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
;
char kind
; int cx
,cy
;

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

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种:

①结合各种定序和存储方法,在遍历其他的时候顺便求解。

②得到最后一次的答案,反向推回来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: