样例给了我们一个很好的提示。观察样例中 \(1\rightarrow 4\) 的路径,发现 \(4 \rightarrow 5\) 这条边走了两遍,再结合题目描述中不需要保证是简单路径的提示,我们发现:
如果路径两侧分别是 (
\(\rightarrow\) (
和 )
\(\rightarrow\) )
的话,那么中间不管怎么走都可以通过左右横跳来调整成一个合法的括号序列。
总结一下是合法括号序列的条件:
- 首先起点要是
(
,终点要是)
,且二者之间有长为偶数的路径(如果你知道并查集维护二分图的技巧,那这就很简单了) - 能够通过
()()()()()...
的形式直接到达。可以使用并查集维护。 - 起点能够
()()...
地到达一个(
\(\rightarrow\)(
的边,终点反之,也可以用并查集维护。
写一大堆并查集即可。
\(upd:\) 一开始写的时候没有注意,由于图可能不连通,所以要对每一个连通块分别判一次奇环。
代码
#include<bits/stdc++.h>
using namespace std;
inline void rd(){}
template<typename T,typename ...U>
inline void rd(T &x,U &...args){
char ch=getchar();
T f=1;x=0;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x*=f;rd(args...);
}
const int N=5e5+5;
int n,m,q,v[N];
struct Edge{
int x,y;
}e[N];
int fa[N<<1],fa1[N],fa2[N],fa3[N];
int tag1[N],tag2[N],jh[N];
inline int fd(int *fa,int x){
if(fa[x]==x)return x;
return fa[x]=fd(fa,fa[x]);
}
int ans[N];
string s;
signed main(){
rd(n,m,q);
cin>>s;
for(int i=0;i<n;i++){
if(s[i]=='('){
v[i+1]=1;
}else v[i+1]=-1;
}
for(int i=1;i<=n;i++)fa1[i]=fa2[i]=fa3[i]=i;
for(int i=1;i<=n*2;i++)fa[i]=i;
for(int i=1;i<=m;i++){
rd(e[i].x,e[i].y);
int x=e[i].x,y=e[i].y;
if(fd(fa,x)!=fd(fa,y+n))fa[fd(fa,x)]=fd(fa,y+n);
if(fd(fa,y)!=fd(fa,x+n))fa[fd(fa,y)]=fd(fa,x+n);
if(!(v[x]==-1&&v[y]==-1))
if(fd(fa1,x)!=fd(fa1,y))fa1[fd(fa1,x)]=fd(fa1,y);
if(!(v[x]==1&&v[y]==1))
if(fd(fa2,x)!=fd(fa2,y))fa2[fd(fa2,x)]=fd(fa2,y);
if(!(v[x]==-1&&v[y]==-1)&&!(v[x]==1&&v[y]==1))
if(fd(fa3,x)!=fd(fa3,y))fa3[fd(fa3,x)]=fd(fa3,y);
}
for(int i=1;i<=m;i++){
int x=e[i].x,y=e[i].y;
if(fd(fa,x)==fd(fa,x+n))jh[fd(fa,x)]=1;
if(fd(fa,y)==fd(fa,y+n))jh[fd(fa,y)]=1;
}
for(int i=1;i<=m;i++){
int x=e[i].x,y=e[i].y;
if(v[x]==1&&v[y]==1)
tag1[fd(fa1,x)]=1;
if(v[x]==-1&&v[y]==-1)
tag2[fd(fa2,x)]=1;
}
for(int i=1;i<=q;i++){
int x,y;rd(x,y);
if(fd(fa,x)!=fd(fa,y)&&fd(fa,x)!=fd(fa,y+n))continue;
if(v[x]!=1||v[y]!=-1)continue;
if((!jh[fd(fa,x)])&&(fd(fa,x)==fd(fa,y)))continue;
if(fd(fa3,x)==fd(fa3,y))ans[i]=1;
else if(tag1[fd(fa1,x)]&&tag2[fd(fa2,y)])ans[i]=1;
}
for(int i=1;i<=q;i++)printf("%d",ans[i]);
printf("\n");
return 0;
}
标签:...,ch,题解,查集,R8,P10572,路径,rightarrow
From: https://www.cnblogs.com/11-twentythree/p/18240937