2022牛客多校3 F 割点 点双联通分量 缩点
很久没有写图论了。
题意:一张图,每次给出一个点对求是否存在以这个s1为首s2为尾的排列使得对于任意的i(1<=i<=n-1)
1~i i+1~n分别各自联通。
先考虑一些特殊情况这样可以使得思考总保持在一个特定情况下。
1 图不连通 一定不行。
2 整张图只有两个点一定可以
思考题目中的条件 和割点有关。
那么容易想到如果整张图没有割点 那么一定可以。但实际上这个东西也许要特殊构造没有那么显然的可以证明。
3 无割点一定可以。
一般的我们考虑正常的图,考虑求完割点后缩点,如果此时图不是一条链即存在度数大于3的点 那从s1总会到达这个点 那么s2就一定过不去其他某个分支。
那么不是链的情况就可以被判掉了
再考虑如果某个点事割点也一定不行。
再考虑s1,s2一定需要在链的两端就做完了。
缩点是指若干个点双联通分量+割点形成的图。
实际上可以不加上割点考虑到没有度数大于3的点存在那么每个割点作用是直接将两个点双连在一起自然把割点给省掉。
本质上缩点只是一个说法,关键是从点双出发来处理问题。
code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 100000001
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define y(w) t[w].y
#define x(w) t[w].x
#define z(w) t[w].z
#define id(cc) s[cc].id
#define S second
#define mod 1000000007
#define sc(A) scanf("%d",&A)
#define scs(A) scanf("%s",A);
#define put(A) printf("%d\n",A)
#define min(x,y) (x>=y?y:x)
#define max(x,y) (x>=y?x:y)
using namespace std;
const int MAXN=200010,maxn=1000010;
int n,m,len,Q,cnt,top,sum;
int d[MAXN],s1,s2;
int w1[MAXN],w2[MAXN],cur[MAXN],dfn[MAXN],low[MAXN],s[MAXN];
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1];
vector<int>g[MAXN],f[MAXN];
inline void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
inline void dfs(int x)
{
dfn[x]=low[x]=++cnt;
s[++top]=x;
int w=0;
go(x)
{
if(!dfn[tn])
{
++w;dfs(tn);
low[x]=min(low[x],low[tn]);
if(low[tn]>=dfn[x])
{
int y=0;
++sum;cur[x]=1;
g[sum].pb(x);
f[x].pb(sum);
while(y!=tn)
{
y=s[top--];
g[sum].pb(y);
f[y].pb(sum);
}
}
}
else
{
low[x]=min(low[x],dfn[tn]);
}
}
if(x==1&&w==1)cur[x]=0;
}
int main()
{
freopen("1.in","r",stdin);
sc(n);sc(m);
rep(1,m,i)
{
int x,y;
sc(x);sc(y);
add(x,y);add(y,x);
}
sc(Q);
if(n==2)
{
rep(1,Q,i)puts("YES");
return 0;
}
int flag=0;
dfs(1);
rep(1,n,i)if(!dfn[i])flag=1;
if(flag)
{
rep(1,Q,i)puts("NO");
return 0;
}
if(sum==1)
{
rep(1,Q,i)puts("YES");
return 0;
}
rep(1,n,i)
{
if(f[i].size()>2)flag=-1;
if(f[i].size()==1)continue;
for(int j=0;j<f[i].size();++j)++d[f[i][j]];
}
rep(1,sum,i)
{
if(d[i]>=3)flag=-1;
if(d[i]==1&&s1&&!s2)s2=i;
if(d[i]==1&&!s1)s1=i;
}
if(flag==-1)
{
rep(1,Q,i)puts("NO");
return 0;
}
rep(0,g[s1].size()-1,i)w1[g[s1][i]]=1;
rep(0,g[s2].size()-1,i)w2[g[s2][i]]=1;
rep(1,Q,i)
{
int x,y;
sc(x);sc(y);
if(w1[x]&&w2[y]&&cur[x]!=1&&cur[y]!=1)
{
puts("YES");
continue;
}
if(w2[x]&&w1[y]&&cur[x]!=1&&cur[y]!=1)
{
puts("YES");
continue;
}
puts("NO");
}
return 0;
}
还没调就过了,我很不认可。