加载中...

点双代补题

https://ac.nowcoder.com/acm/contest/33188/F

既然是取点就该想到点双。
如果全图就是一个点双,显然可行。
如果只有 2 个点,显然可行。
若全图有多个点双,如果二者都在同个点双,显然不可行。
枚举 1 ~ n−1 的过程中点的变化是连续的,但如果有个人开始没占到某个割点,占到时肯定会把被该点分割的点集一并算在自己的范围内,不满足条件。
缩点后如果不是一条链,二人在度数为 3 的点双中争抢节点时,必然会产生上述情况。
需要图缩点后时一条链,且二者位于链两端的点集中且不为割点才满足条件。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define IL inline
#define LL long long
#define pb push_back
using namespace std;
const int N=2e5+3;
struct hh{
	int to,nxt;
}e[N<<1];
int n,m,q,num,col,tp,sta[N],fir[N],dfn[N],low[N],val[N];
vector<int>e1[N],e2[N];
IL int in(){
    char c;int f=1;
    while((c=getchar())<'0'||c>'9')
      if(c=='-') f=-1;
    int x=c-'0';
    while((c=getchar())>='0'&&c<='9')
      x=x*10+c-'0';
    return x*f;
}
IL void add(int x,int y){e[++num]=(hh){y,fir[x]},fir[x]=num;}
void tarjan(int u){
	dfn[u]=low[u]=++num,sta[++tp]=u;
	for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
	  if(!dfn[v]){
	  	tarjan(v),low[u]=min(low[u],low[v]);
	  	if(dfn[u]<=low[v]){
	  		++col;
	  		while(sta[tp+1]!=v)
	  		  e1[sta[tp]].pb(col),
	  		  e2[col].pb(sta[tp--]);
	  		e1[u].pb(col),e2[col].pb(u);
	  	}
	  }
	  else low[u]=min(low[u],dfn[v]);
}
IL void print(int op){for(int i=1;i<=q;++i) puts(op?"YES":"NO");exit(0);}
int main()
{
	int x,y,z;
	n=in(),m=in();
	for(int i=1;i<=m;++i)
	  x=in(),y=in(),add(x,y),add(y,x);
	q=in(),num=0,tarjan(1),num=0;
	if(n==2) print(1);
	for(int i=1;i<=n;++i)
	  if(!dfn[i]||e1[i].size()>2) print(0);
	if(col==1) print(1);
	for(int i=1;i<=col;++i){
		int deg=0;
		for(int j=0;j<e2[i].size();++j)
		  deg+=e1[e2[i][j]].size()-1;
		if(deg>2) print(0);
		if(deg==1){
			++num;
			for(int j=0;j<e2[i].size();++j)
			  if(e1[e2[i][j]].size()==1) val[e2[i][j]]=num;
		}
	}
	while(q--) puts(val[in()]+val[in()]^3?"NO":"YES");
  return 0;
}

posted @ 2022-08-31 22:52  liang302  阅读(21)  评论(0编辑  收藏  举报