[并查集][二分图][广搜]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)

代码

#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");
}
View Code

 

posted @ 2021-03-25 16:54  Vagari  阅读(59)  评论(0编辑  收藏  举报