UOJ#465. 【HNOI2019】校园旅行 其他
原文链接www.cnblogs.com/zhouzhendong/p/UOJ465.html
前言
tmd并查集写挂,调到自闭。
cly和我写挂了同一个地方。
一下救了两个人感觉挺开心。
题解
首先直接写 bfs/记忆化dfs 可以容易地得到一个 $O(m^2)$ ,或者 $O(nm)$ 的做法。常数不大的情况下应该可以得到 70 分。
注意到本题中不要求简单路径,同一条边可以经过多次。
这意味着,我们可以在有边相连的两个同色节点之间来回走。
那么,假设两个点在同一个同色连通块,那么从其中一个点到另一个点的路径的有效信息本质只有两种:是否存在长度为奇数的路径、是否存在长度为偶数的路径。
于是,对于一个同色连通块,我们只需要保留一个带奇环的基环树即可,如果没有满足条件的基环树,就保留一个树。
然后我们考虑拆除所有连接同色点的边,留下所有连接不同色点的边。
类似的,对于剩下的边,我们只要留下一座边数尽量多的生成森林即可。
我丝薄了,写了个并查集维护。其实直接 dfs 就好了。
于是剩下 $O(n)$ 条边,只要做一做最开始的暴力就好了。
时间复杂度 $O(m\cdot \alpha(n) + n^2)$ 或 $O(m + n ^2)$ 。
代码
#pragma GCC optimize("Ofast","inline") #include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) #define For(i,a,b) for (int i=a;i<=b;i++) #define Fod(i,b,a) for (int i=b;i>=a;i--) #define pb(x) push_back(x) #define mp(x,y) make_pair(x,y) #define fi first #define se second #define real __zzd001 #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I') #define outval(x) printf(#x" = %d\n",x) #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("") #define outtag(x) puts("----------"#x"----------") #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\ For(_v2,L,R)printf("%d ",a[_v2]);puts(""); using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef vector <int> vi; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch=='-',ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=5005,M=500005; int n,m,q; vector <int> e[N]; char s[N]; struct Edge{ int x,y; }E[M]; int r[N]; namespace S1{ int fa[N],d[N]; void init(){ For(i,1,n) fa[i]=i; clr(d); } int getf(int x){ if (fa[x]==x) return x; int f=getf(fa[x]); d[x]^=d[fa[x]]; return fa[x]=f; } } namespace S2{ int fa[N]; void init(){ For(i,1,n) fa[i]=i; } int getf(int x){ return fa[x]==x?x:fa[x]=getf(fa[x]); } } int f[N][N]; int qx[N*N],qy[N*N],head=0,tail=0; void Push(int x,int y){ if (x>y) swap(x,y); if (!f[x][y]){ f[x][y]=1; tail++; qx[tail]=x; qy[tail]=y; } } int main(){ n=read(),m=read(),q=read(); scanf("%s",s+1); For(i,1,m) E[i].x=read(),E[i].y=read(); S1::init(),S2::init(); For(i,1,m){ int x=E[i].x,y=E[i].y; if (s[x]==s[y]){ if (S1::getf(x)!=S1::getf(y)){ e[x].pb(y),e[y].pb(x); S1::d[S1::getf(x)]=S1::d[x]^S1::d[y]^1; S1::fa[S1::fa[x]]=S1::getf(y); } } else { if (S2::getf(x)!=S2::getf(y)){ e[x].pb(y),e[y].pb(x); S2::fa[S2::getf(x)]=S2::getf(y); } } } For(i,1,m){ int x=E[i].x,y=E[i].y; S1::getf(x),S1::getf(y); if (s[x]==s[y]&&!r[S1::getf(x)]&&S1::d[x]==S1::d[y]){ r[S1::getf(x)]=1; e[x].pb(y),e[y].pb(x); } } For(i,1,n) Push(i,i); For(i,1,m) if (s[E[i].x]==s[E[i].y]) Push(E[i].x,E[i].y); while (head<tail){ head++; int x=qx[head],y=qy[head]; for (auto a : e[x]) for (auto b : e[y]) if (s[a]==s[b]) Push(a,b); } while (q--){ int x=read(),y=read(); if (x>y) swap(x,y); puts(f[x][y]?"YES":"NO"); } return 0; }