Description
“我有个愿望,我希望在灿烂千阳时遇见你。”
这是个有n个点的世界,有m条无向边连接着这n个点,但是不保证点之间能够互相到达。
“这个世界的夕阳,只在奇数长的简单路径的尽头。”一个神如是说。
于是我想知道对于一个点对(x,y),x到y之间的所有简单路径中是否存在长度为奇数的路径,只有这样,我才能找到存在有夕阳的路。
Data Constraint
对于50%的数据,1≤n,m,q≤500
对于100%的数据,,1≤n,q,m≤100000
保证没有自环与重边。
Solution
显然,对于一个边数为奇数的简单环奇环,它的两两点之间的奇偶性是可以改变的。所以我们在tarjan中判断一个强连通分量是否含有奇环,假如有,那么整个强连通分量的奇偶性也是可改变的。最后我们判断一下询问的两个点之间是否含有奇环即可。
代码
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=200006;
int m,n,i,t,j,k,l,x,y,z,num,ln;
int first[maxn],last[maxn],next[maxn],f[maxn][20],g[maxn][20];
int d[maxn],bz[maxn],deep[maxn],fa[maxn],dfn[maxn],low[maxn],a[maxn],b[maxn];
void lian(int x,int y){
last[++num]=y;next[num]=first[x];first[x]=num;
}
void dg(int x,int y){
int t,k=++d[0];bz[x]=1;deep[x]=deep[y]+1;dfn[x]=low[x]=++num;d[d[0]]=x;f[x][0]=y;
bool bz2=true;
for (t=first[x];t;t=next[t]){
if (last[t]==y) continue;
if (bz[last[t]]==2) continue;
if (!bz[last[t]]) dg(last[t],x);
else if (!((deep[x]-deep[last[t]])%2))g[x][0]=1;
low[x]=min(low[x],low[last[t]]);
}
if (dfn[x]!=low[x]) return;
for (t=k;t<=d[0];t++){
bz[d[t]]=2,fa[d[t]]=x;
if (g[d[t]][0]) bz2=false;
}
if (bz2) {d[0]=k-1;return;}
for (t=k;t<=d[0];t++)
g[d[t]][0]=1;
g[x][0]=0;
}
int lca(int x,int y){
int i,j;
if (deep[x]<deep[y]) swap(x,y);
for (j=ln;j>=0;j--)
if(deep[f[x][j]]>=deep[y]) k+=g[x][j],x=f[x][j];
if (x==y) return x;
for (j=ln;j>=0;j--)
if(f[x][j]!=f[y][j]) k+=g[x][j]+g[y][j],x=f[x][j],y=f[y][j];
k+=g[x][0]+g[y][0];
return f[x][0];
}
int main(){
freopen("sunset.in","r",stdin);freopen("sunset.out","w",stdout);
//freopen("data.in","r",stdin);freopen("data.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
scanf("%d%d",&x,&y),lian(x,y),lian(y,x);
scanf("%d",&m);
num=0;
for (i=1;i<=n;i++)
if (!bz[i]) dg(i,0);
ln=log(n)/log(2);
for (j=1;j<=ln;j++)
for (i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1],g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1];
for (i=1;i<=m;i++){
scanf("%d%d",&x,&y);k=0;
t=lca(x,y);
if (!t){
printf("No\n");
continue;
}
t=deep[x]+deep[y]-2*deep[t];
if (t%2 || k) printf("Yes\n");
else printf("No\n");
}
}