• "蔚来杯"2022牛客暑期多校训练营3 F Fief题解


    F Fief

    这个题是比赛的时候放弃的题...
    给定一个无向图,每次询问两个点a,b,问是否存在一个排列,起点是a,终点是b。且每个前缀后缀都联通。
    考虑一个简单环上的一个点出发,到达任意一个点都是满足题意的。从环这个角度出发去想的话,我们想到的就是点双和边双,可边双是把图分成若干个部分,而我们想要的是这个图仍然联通来着,那么从点双出发,我们vcc缩点,之后图就变成一颗树,每个节点要么代表一个vcc,要么代表一个割点。我们发现如果存在分叉口的话,我们发现后缀是不连通的。所以说明建完图后,只能是个链。否则,就不行。而且只有首尾的两个vcc里的点才行。

    点击查看代码
    #include<bits/stdc++.h>
    using namespace std;
    const int N=4e5+10;
    int n,m,dfn[N],low[N],cnt,num,Stack[N],top,root;
    int new_id[N],du[N],vis[N];
    vector<int>son[N];
    vector<int>vcc[N];
    bool cut[N];
    inline void tarjan(int x)
    {
    	dfn[x]=low[x]=++num;
    	Stack[++top]=x;
    	if(x==root&&son[x].size()==0) 
    	{
    		vcc[++cnt].push_back(x);
    		return;
    	}
    	int flag=0;
    	for(auto y:son[x])
    	{
    		if(!dfn[y])
    		{
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    			if(low[y]>=dfn[x])
    			{
    				flag++;
    				if(x!=root||flag>1) cut[x]=true;
    				cnt++;
    				int z;
    				do
    				{
    					z=Stack[top--];
    					vcc[cnt].push_back(z);
    				}while(z!=y);
    				vcc[cnt].push_back(x);
    			}	
    		}
    		else low[x]=min(low[x],dfn[y]); 
    	}
    }
    inline bool check()
    {
    	int cnt=0;
    	for(int i=1;i<=num;++i) if(du[i]==1) cnt++;
    	if(cnt==2) return true;
    	return false; 
    }
    int main()
    {
    //	freopen("1.in","r",stdin); 
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;++i) 
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		son[x].push_back(y);
    		son[y].push_back(x);
    	}
    	int pg=0;
    	for(int i=1;i<=n;++i) if(!dfn[i]) root=i,tarjan(i),pg++;
    	num=cnt;
    	for(int i=1;i<=n;++i)
    		if(cut[i]) new_id[i]=++num;
    	for(int i=1;i<=cnt;++i)
    	{
    		for(auto x:vcc[i])
    		{
    			if(cut[x])
    			{
    				du[i]++;
    				du[new_id[x]]++;
    			}
    		}
    	}
    	bool ischain=check();	
    	if(ischain)
    	{
    		int ps=0;
    		for(int i=1;i<=cnt;++i) 
    		{
    			if(du[i]==1)
    			{
    				ps++;
    				for(auto x:vcc[i]) if(!cut[x]) vis[x]=ps;
    			}
    		}
    	}
    	scanf("%d",&m);
    	if(cnt==1)
    	{
    		for(int i=1;i<=m;++i) puts("YES");
    		return 0;
    	}
    	if(pg!=1)
    	{
    		for(int i=1;i<=m;++i) puts("NO");
    		return 0;
    	}
    	for(int i=1;i<=m;++i)
    	{
    		int a,b;
    		scanf("%d%d",&a,&b);
    		if(ischain&&vis[a]!=0&&vis[b]!=0&&vis[a]!=vis[b]) puts("YES");
    		else puts("NO");
    	}
    	return 0; 
    }
    
  • 相关阅读:
    Automatically Display Menu on Hover
    WPF自学教程系列1:如何将WPF空间嵌套到Form窗口?
    NET中的内存管理,GC机制,内存释放过程. 转载
    C++ 初始化和赋值的区别
    2.尽量用const, enum, inline代替#define Prefer const, enum, inline to #define.
    1.视C++为一个语言联邦 View C++ as a federation of languages
    C++内存对齐
    C++ class和struct的区别
    redhat AS5 Samba服务配置
    windowsXP & 2003 加固
  • 原文地址:https://www.cnblogs.com/gcfer/p/16524284.html
Copyright © 2020-2023  润新知