题意
已知一个无向图,现在有若干个询问请你回答:
1.A B G1 G2求从A到B是否能不通过G1-G2这条已经存在的边
2.A B C求从A到B能否不通过C这个点
题解
其实很简单的一个题啊,想一想就想到了
但是我的“写法是不够优秀的”,于是去看了一下别人的写法,因此还是有收获的
明显的TJ然后分类讨论啊
本来就不连通的明显用并查集搞一搞就可以了
考虑割掉一个点的时候,被他分割出去的连通块,如果两个点在一个块里面,那么肯定是yes
否则如果如果一个在块里面,一个在块外面就是no
这么怎么弄呢?我一开始想的是弄dfs序,然后线段树上面子树修改
但这样会多一个log,其实我们只需要维护一个子树的并查集就可以了
然后块怎么弄呢?
我们可以对于打标记啊
标记的意思是说我们这个点会被割成一个块
而不是说某个点是不是割点
这个处理方法也很妙啊
时间复杂度O(n)
CODE:
#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int N=500005*2;
struct qq{int x,y,last;}e[N];
int num,last[N];
int n,m,q;
int F[N];//并查集
void init (int x,int y)
{
num++;
e[num].x=x;e[num].y=y;
e[num].last=last[x];
last[x]=num;
}
vector<int> c1[N],c2[N];
int find (int x){return F[x]==x?F[x]:F[x]=find(F[x]);}
int dfn[N],low[N],id;
bool ans[N];
int A[N],B[N];
int fa[N];
void Dfs (int x,int ff)
{
fa[x]=ff;
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
if (y==ff) continue;
if (fa[y]!=-1) continue;
Dfs(y,x);
}
}
bool cut[N];//是否是被割出去的一个块
bool check (int x,int xx,int yy)
{
if (find(xx)==find(yy)) return true;
if (dfn[xx]<dfn[x]&&dfn[yy]<dfn[x]) return true;
return false;
}
void dfs (int x)
{
low[x]=dfn[x]=++id;
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
if (y==fa[x]) continue;
if (dfn[y]==0)
{
dfs(y);
low[x]=min(low[x],low[y]);
if (low[y]>=dfn[x]) cut[y]=true;
}
else low[x]=min(low[x],dfn[y]);
}
for (int u=0;u<c2[x].size();u++)
{
int id=c2[x][u];
int xx=A[id],yy=B[id];
// printf("%d %d %d\n",x,xx,yy);
if (xx==x||yy==x) {ans[id]=false;continue;}
if (check(x,xx,yy)) continue ;
if (dfn[xx]>dfn[x]&&cut[find(xx)]) ans[id]=false;
if (dfn[yy]>dfn[x]&&cut[find(yy)]) ans[id]=false;
}
for (int u=last[x];u!=-1;u=e[u].last)
{
int y=e[u].y;
if (dfn[y]>dfn[x]) F[find(y)]=find(x);
}
if (dfn[x]==low[x])
{
for (int u=0;u<c1[x].size();u++)
{
int id=c1[x][u];
int xx=A[id],yy=B[id];
if (check(x,xx,yy)) continue;
ans[id]=false;
}
}
}
int main()
{
memset(cut,false,sizeof(cut));
id=0;memset(dfn,0,sizeof(dfn));
num=0;memset(last,-1,sizeof(last));
scanf("%d%d",&n,&m);
for (int u=1;u<=n;u++) F[u]=u;
for (int u=1;u<=m;u++)
{
int x,y;
scanf("%d%d",&x,&y);
init(x,y);init(y,x);
int fx=find(x),fy=find(y);F[fx]=fy;
}
memset(fa,-1,sizeof(fa));
for (int u=1;u<=n;u++)
if (fa[u]==-1)
Dfs(u,0);
memset(ans,true,sizeof(ans));
scanf("%d",&q);
for (int u=1;u<=q;u++)
{
int op;
scanf("%d%d%d",&op,&A[u],&B[u]);
if (op==1)
{
int x,y;
scanf("%d%d",&x,&y);
if (find(A[u])!=find(B[u])) {ans[u]=false;continue;}
if (fa[x]!=y) swap(x,y);
if (fa[x]!=y) continue;
c1[x].push_back(u);
}
if (op==2)
{
int x;
scanf("%d",&x);
if (find(A[u])!=find(B[u])) {ans[u]=false;continue;}
c2[x].push_back(u);
}
}
for (int u=1;u<=n;u++) F[u]=u;
for (int u=1;u<=n;u++)
if (fa[u]==0)
dfs(u);
for (int u=1;u<=q;u++)
{
if (ans[u]) printf("yes\n");
else printf("no\n");
}
return 0;
}