2019 China Collegiate Programming Contest Qinhuangdao Onsite F. Forest Program(点双连通)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019 China Collegiate Programming Contest Qinhuangdao Onsite F. Forest Program(点双连通)相关的知识,希望对你有一定的参考价值。

LINK

套用点双连通模板即可

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6+10;
const int mod = 998244353;
struct edge{ int to,nxt; }d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){ d[++cnt] = ( edge ){v,head[u]},head[u] = cnt; }
int n,m;
int dfn[maxn],low[maxn],cut[maxn],stac[maxn];
int dc,top,id,child,root;
vector<int>dcc[maxn];
void tarjan(int u,int fa)
{
	dfn[u] = low[u] = ++id, stac[++top]=u;
	if( u==root&&!head[u] )//孤立点
	{
		dcc[++dc].push_back(u);
		return;	
	} 
	int child=0;
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v=d[i].to;
		if( !dfn[v] )
		{
			tarjan(v,u);
			low[u]=min( low[u],low[v] );
			if( low[v]>=dfn[u] )//不通过u,v无法回到更浅的节点
			{
				child++;
				int temp; ++dc;//发现割点,开始弹栈 
				//注意,如果u是父节点且只有1个儿子,不算割点,但也会开始弹栈 
				while( temp=stac[top--] )
				{
					dcc[dc].push_back(temp);
					if( temp==v )	break;//直到遇到v 
				}
				dcc[dc].push_back(u);
			}	
		}
		else if( v!=fa )	low[u]=min(low[u],dfn[v] );
	}
	if( u==fa && child>=2 )	cut[u] = 1;
}
int quick(int x,int n)
{
	int ans = 1;
	for( ; n ; n>>=1,x=1ll*x*x%mod )
		if( n&1 )	ans = 1ll*ans*x%mod;
	return ans;
}
signed main()
{
	cin >> n >> m;
	for(int i=1;i<=m;i++)
	{
		int l,r; scanf("%d%d",&l,&r);
		add(l,r); add(r,l);
	}
	for(int i=1;i<=n;i++)
		if( !dfn[i] )	tarjan(i,i);
	int ans = 1,num = 0;
	for(int i=1;i<=dc;i++)
	{
		if( dcc[i].size()>=3 )
		{
			num += dcc[i].size();
			ans = 1ll*ans*( quick(2,dcc[i].size() )-1 )%mod;
		}
	}
	ans = 1ll*ans*quick(2,m-num)%mod;
	cout << ( ans%mod+mod )%mod;
}
/*
11 13
1 2
1 3 
2 4
3 4
4 5
4 6
6 7
7 8
5 8
8 9
8 10
10 11
9 11

*/

也许 d f s dfs dfs更好理解

把路径上的点标记起来,走到原来走过的点说明是环

倒回去算长度

离开这个点的时候也标记一下说明不在路径上了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=998244353;
#define mst(a,b) memset(a,b,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
int f[N],vis[N];
vector<int>e[N];
ll ksm(ll a,ll n){
	ll ans=1;
	while(n){
		if(n&1) ans=ans*a%mod;
		a=a*a%mod;
		n>>=1;
	}
	return ans;
}
ll ans=1,cnt;
void dfs(int u,int fa){
	vis[u]=1;
	for(int v:e[u]){
		if(v==fa) continue;
		if(!vis[v]) f[v]=u,dfs(v,u);
		else if(vis[v]==2) continue;
		else {
			int x=1,now=u;
			while(now!=v){
				x++,now=f[now];
			}
			cnt+=x;
			ans=ans*(ksm(2,x)-1)%mod; 
		}
	}
	vis[u]=2;
} 
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		e[u].pb(v),e[v].pb(u);
	} 
	for(int i=1;i<=n;i++){
		if(!vis[i]) dfs(i,0); 
	}
	printf("%lld\\n",ans*ksm(2,m-cnt)%mod);
	return 0;
}

以上是关于2019 China Collegiate Programming Contest Qinhuangdao Onsite F. Forest Program(点双连通)的主要内容,如果未能解决你的问题,请参考以下文章

The 2019 China Collegiate Programming Contest Harbin Site I. Interesting Permutation

The 2019 China Collegiate Programming Contest Harbin Site K. Keeping Rabbits

The 2019 China Collegiate Programming Contest Harbin Site J. Justifying the Conjecture

2019 China Collegiate K. MUV LUV UNLIMITED(思维,博弈)

2019 China Collegiate Programming Contest Qinhuangdao Onsite F. Forest Program(点双连通)

The 2019 China Collegiate Programming Contest Harbin Site I - Interesting Permutation 思维