[并查集][二分图][广搜]luogu P5292 [HNOI2019]校园旅行
题面
https://www.luogu.com.cn/problem/P5292
问在无向图中某点对是否有边权组合为01回文串的路径
分析
考虑暴力,就是往队列里加入路径的首尾(一个0/1或者两个0/1),BFS扩展
复杂度 O(m^2)
可以发现因为可以走非简单路径,可以通过绕同一条边来获得长度一致的部分,所以能否到达只跟图的奇偶性有关
考虑图论中奇偶性相关的,显然有二分图:奇偶性不变
那么我们独立考虑0-0边,1-1边,0-1边,把原图割为三个图
如果是二分图,不难证明只需要保留该二分图的一个生成树,也能保证奇偶性不变
如果不是二分图,考虑在建立生成树之后加入一个自环,因为如果不是二分图,那么图中必然存在奇环改变了奇偶性,我们加入一个自环来调整这个奇偶性即可
最后因为要么建立了生成树,要么是生成树加一个自环,所以边数级别是 O(n) ,复杂度降到 O(n^2)
代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; const int N=5e3+10; const int M=5e5+10; struct Graph { int v,nx; }g[2*M+N]; int cnt,list[N],u[M],v[M],bel[N],inbi[N],f[N][2]; bool col[N],w[N],vis[N][N]; int n,m,Q; char s[N]; struct Path { int u,v; }; queue<Path> q; inline int read(){ register int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } inline void Add(int u,int v) {g[++cnt]=(Graph){v,list[u]};list[u]=cnt;} inline int Get_F(int x,int id) {return x==f[x][id]?x:f[x][id]=Get_F(f[x][id],id);} inline void DFS(int u) { for (register int i=list[u];i;i=g[i].nx) if (!bel[g[i].v]) col[g[i].v]=col[u]^1,bel[g[i].v]=bel[u],DFS(g[i].v); else if (col[g[i].v]==col[u]) inbi[bel[u]]=1; } inline void BFS() { while (!q.empty()) { register Path now=q.front();q.pop(); for (register int i=list[now.u];i;i=g[i].nx) for (register int j=list[now.v];j;j=g[j].nx) if (!vis[g[i].v][g[j].v]&&w[g[i].v]==w[g[j].v]) vis[g[i].v][g[j].v]=vis[g[j].v][g[i].v]=1,q.push((Path){g[i].v,g[j].v}); } } int main() { n=read();m=read();Q=read(); scanf("%s",s+1); for (register int i=1;i<=n;i++) w[i]=s[i]-'0',f[i][0]=f[i][1]=i,vis[i][i]=1,q.push((Path){i,i}); for (register int i=1;i<=m;i++) { u[i]=read();v[i]=read(); if (w[u[i]]==w[v[i]]) Add(u[i],v[i]),Add(v[i],u[i]); } for (register int i=1;i<=n;i++) if (!bel[i]) DFS(bel[i]=i); cnt=0;memset(list,0,sizeof list); for (register int i=1,x,y;i<=m;i++) { register bool tp=(w[u[i]]^w[v[i]]); if ((x=Get_F(u[i],tp))==(y=Get_F(v[i],tp))) continue; f[x][tp]=y;Add(u[i],v[i]);Add(v[i],u[i]); if (!tp) vis[u[i]][v[i]]=vis[v[i]][u[i]]=1,q.push((Path){u[i],v[i]}); } for (register int i=1;i<=n;i++) if (inbi[i]) inbi[i]=0,Add(i,i); BFS(); for (register int i=1,x,y;i<=Q;i++) x=read(),y=read(),printf(vis[x][y]?"YES\n":"NO\n"); }
在日渐沉没的世界里,我发现了你。