NOIP模拟赛 夕阳
题目描述
“我有个愿望,我希望在灿烂千阳时遇见你。”
这是个有n个点的世界,有m条无向边连接着这n个点,但是不保证点之间能够互相到达。
“这个世界的夕阳,只在奇数长的简单路径的尽头。”一个神如是说。
于是我想知道对于一个点对(x,y),x到y之间的所有简单路径中是否存在长度为奇数的路径,只有这样,我才能找到存在有夕阳的路。
输入
第一行两个数n和m表示点的个数和边的条数。
接下来m行,每行两个数x,y表示x和y之间存在一条无向边。
接下来一行一个整数q表示询问的个数。
下面q行每行两个整数x,y表示一组询问,问x到y的所有简单路径中是否存在有长度为奇数的路径
输出
对于每组询问x,y,如果x与y之间存在一条长度为奇数的简单路径那么输出Yes否则输出No
样例输入
7 7 1 3 1 4 2 3 2 4 5 6 6 7 7 5 8 1 2 1 3 1 4 2 4 1 5 5 6 5 7 6 7
样例输出
No
Yes
Yes
Yes
No
Yes
Yes
Yes
数据范围
对于50%的数据,1≤n,m,q≤500
对于100%的数据,,1≤n,q,m≤100000
保证没有自环与重边。
题解:
若对原图解出生成树森林,那么询问点对(x,y)见是否有简单路径长度为奇数,可以看作求点对(x,y)是否有边在奇环上。
于是问题转化为判断是否有边在奇环中,这里解图的强联通分量,对于一个强联通分量,若其中有边在奇环上,那么分量中的所有边都在某个奇环上。
为了在分量中找到在奇环上的边,对图作tarjan算法,若点对(x,y)的深度的奇偶性相同,那么x和y的路径上的边都在奇环中。
#include<math.h> #include<stdio.h> #include<string.h> #define buf 100001 #define MAXBUF 1<<9 #define dmin(a,b) ((a)<(b)?(a):(b)) inline void swp(int &x,int &y){ x^=y, y^=x, x^=y; } char B[MAXBUF],*S=B,*T=B; inline char gt(){ if(S==T){ T=(S=B)+fread(B,1,MAXBUF,stdin); if(S==T) return 0; } return *S++; } inline void F(int &x){ x=0;int c=gt(),f=1; for(;c<48||c>57;c=gt()) if(!(c^45)) f=-1; for(;c>47&&c<58;c=gt()) x=(x<<1)+(x<<3)+c-48; x*=f; } struct Pointer{ int to; Pointer *nxt; }*fst[buf]; Pointer mem[buf<<1],*tot=mem; inline void link(int a,int b){ *++tot=(Pointer){b,fst[a]},fst[a]=tot; *++tot=(Pointer){a,fst[b]},fst[b]=tot; } bool odd[buf]; int bin[20],n,m,dfn[buf],dep[buf],fa[buf][20],tim,s[buf],top,pb[buf],timer,low[buf],scn[buf],scx; void tarjan(int x){ pb[++top]=x; dfn[x]=low[x]=++timer; for(int i=1;i<=tim;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for(Pointer *iter=fst[x];iter;iter=iter->nxt) if(iter->to^fa[x][0]) if(!dfn[iter->to]) fa[iter->to][0]=x, dep[iter->to]=dep[x]+1, tarjan(iter->to), low[x]=dmin(low[x],low[iter->to]); else if(!scn[iter->to]){ low[x]=dmin(low[x],dfn[iter->to]); if(!((dep[iter->to]&1)^(dep[x]&1))) odd[x]=1; } if(!(dfn[x]^low[x])){ bool f=0; int v=top; for(;pb[v]^x;) f|=odd[pb[v--]]; if(f) for(v++;v<=top;v++) s[pb[v]]++; ++scx; do v=pb[top--], scn[v]=scx; while(v^x); } } void dfs(int x){ for(Pointer *iter=fst[x];iter;iter=iter->nxt) if(!(fa[iter->to][0]^x)) s[iter->to]+=s[x], dfs(iter->to); } int lca(int x,int y){ if(dep[x]<dep[y]) swp(x,y); for(int i=tim;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if(!(x^y)) return x; for(int i=tim;i>=0;i--) if(fa[x][i]^fa[y][i]) x=fa[x][i], y=fa[y][i]; return fa[x][0]; } int main(){ freopen("sunset.in","r",stdin), freopen("sunset.out","w",stdout); F(n),F(m); tim=log(n)/log(2)+1; bin[0]=1; for(int i=1;i<=tim;i++) bin[i]=bin[i-1]<<1; for(int x,y;m;m--) F(x), F(y), link(x,y); for(int i=1;i<=n;i++) if(!dfn[i]) dep[i]=1, fa[i][0]=i, tarjan(i); for(int i=1;i<=n;i++) if(!(fa[i][0]^i)) dfs(i); int q,x,y,t; for(F(q);q;q--){ F(x),F(y); if(fa[x][tim]^fa[y][tim]) puts("No"); else t=lca(x,y), puts(((dep[x]+dep[y]-(dep[t]<<1))&1 ||s[x]+s[y]-(s[t]<<1)>0)? "Yes": "No"); } fclose(stdin), fclose(stdout); }