zoukankan      html  css  js  c++  java
  • SNOI2020 LOJ3323 生成树

    题目传送门

    分析:
    树上问题放仙人掌上考已经很离谱了,仙人掌上加一条边是什么烂玩意??
    本题会反复运用仙人掌的一个公式:
    点-边+环=1
    我们先判断一下(G)是否是一棵仙人掌,如果是就直接把环的大小乘起来就好了
    如果不是,我们就要想办法找到哪一条边在作怪
    先找点双连通分量,肯定会形成若干个环和一个奇奇怪怪的点双
    单独处理这一个奇怪的点双,作为子图(G')处理
    子图(G')大概会出现两种情况,一种是一个大环上面串很多小环,另一种是两个环共用一条边(样例),但其实两者本质相同
    胡乱分析一下,如果一条边的一个端点度数为3,那么这条边就很有嫌疑
    我们把所有这种边放到一起,随机排序(数据挺水可以不用2333)后,暴力删每一条边,检验剩下的图是不是仙人掌
    随机之后找到某一条满足条件的边(E),期望次数是很小的(玄学)
    剩下的图缩点之后加上(E),明显是一个环,而环上每一条边与(E)等效
    一顿加加减减就好了。。。
    剩下的情况就是缩点后的环并不删边,我们删去本来被缩点的某一个小环上的两条边,也会形成生成树
    这种情况在缩点时顺便处理一下
    一顿加加减减就好了。。。
    代码写起来恶心,细节很多,讲不清楚,不理解的看看代码吧。。。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<iostream>
    #include<map>
    #include<string>
    
    #define maxn 1000005
    #define MOD 998244353
    
    using namespace std;
    
    inline int getint()
    {
    	int num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n,m;
    struct node{int u,v;}e[maxn];
    int fir[maxn],nxt[maxn],to[maxn],cnt=1;
    int dfn[maxn],low[maxn],tim,stk[maxn],tp;
    int Pd=1;
    vector<int>scc[maxn],scce[maxn],G,E,VE;
    int scccnt,fa[maxn],tot,T[maxn],P[maxn];
    bool ban[maxn];
    int d[maxn],Cnt,sum;
    
    inline int ksm(int num,int k)
    {
    	int ret=1;
    	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
    	return ret;
    }
    
    inline void newnode(int u,int v)
    {to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
    inline void tarjan(int u,int pre)
    {
    	dfn[u]=low[u]=++tim;stk[++tp]=u;
    	for(int i=fir[u];i;i=nxt[i])if(!ban[i>>1]&&i!=pre)
    	{
    		int v=to[i];
    		if(!dfn[v])
    		{
    			tarjan(v,i^1),low[u]=min(low[u],low[v]);
    			if(low[v]==dfn[u])
    			{
    				int x;tot++,scccnt++,fa[tot]=u;
    				do{x=stk[tp--],scc[scccnt].push_back(x),fa[x]=tot;}while(x!=v);
    				scc[scccnt].push_back(u);
    			}
    			else if(low[v]>dfn[u])tp--,fa[v]=u;
    		}
    		else low[u]=min(low[u],dfn[v]);
    	}
    }
    
    inline void dfs(int u,int pre)
    {
    	dfn[u]=low[u]=++tim;stk[++tp]=u;
    	for(int i=fir[u];i;i=nxt[i])if(!ban[i>>1]&&i!=pre)
    	{
    		int v=to[i];
    		if(!dfn[v])
    		{
    			dfs(v,i^1),low[u]=min(low[u],low[v]);
    			if(low[v]==dfn[u])
    			{
    				int x;scccnt++;
    				do{x=stk[tp--];}while(x!=v);
    			}
    			else if(low[v]>dfn[u])tp--;
    		}
    		else low[u]=min(low[u],dfn[v]);
    	}
    }
    
    inline void solve(int u,int pre)
    {
    	dfn[u]=low[u]=++tim;stk[++tp]=u;
    	for(int i=fir[u];i;i=nxt[i])if(!ban[i>>1]&&i!=pre)
    	{
    		int v=to[i];
    		if(!dfn[v])
    		{
    			solve(v,i^1),low[u]=min(low[u],low[v]);
    			if(low[v]==dfn[u])
    			{
    				int x;scccnt++;
    				do{
    					x=stk[tp--],scc[scccnt].push_back(x);
    					if(d[x]>2)P[scccnt]=scc[scccnt].size();
    				}while(x!=v);
    				scc[scccnt].push_back(u);
    			}
    			else if(low[v]>dfn[u])tp--;
    		}
    		else low[u]=min(low[u],dfn[v]);
    	}
    }
    
    int main()
    {
    	tot=n=getint(),m=getint();
    	for(int i=1;i<=m;i++)
    	{
    		int u=e[i].u=getint(),v=e[i].v=getint();
    		newnode(u,v),newnode(v,u);
    	}
    	tarjan(1,0);
    	for(int p=1;p<=n;p++)for(int i=fir[p];i;i=nxt[i])if(to[i]>p)
    	{
    		int u=p,v=to[i];
    		if(fa[fa[u]]==v)swap(u,v);
    		if(fa[v]==fa[u]||fa[fa[v]]==u)T[fa[v]-n]++,scce[fa[v]-n].push_back(i>>1);
    	}
    	int p=0;
    	for(int i=1;i<=scccnt;i++)if(T[i]!=scc[i].size()){p=i;break;}
    	if(!p)
    	{
    		int ans=1;
    		for(int i=1;i<=scccnt;i++)ans=1ll*ans*scc[i].size()%MOD;
    		printf("%d
    ",ans);
    		return 0;
    	}
    	
    	G=scc[p],E=scce[p];
    	for(int i=1;i<=scccnt;i++)if(i!=p)Pd=1ll*Pd*scc[i].size()%MOD;
    	for(int i=1;i<=scccnt;i++)scc[i].clear(),scce[i].clear();
    	memset(fir,0,sizeof fir),cnt=1;
    	
    	for(int i=0;i<E.size();i++)
    		newnode(e[E[i]].u,e[E[i]].v),newnode(e[E[i]].v,e[E[i]].u),d[e[E[i]].u]++,d[e[E[i]].v]++;
    	for(int i=0;i<E.size();i++)if(d[e[E[i]].u]==3||d[e[E[i]].v]==3)VE.push_back(i+1);
    	int ID=0;
    	for(int t=0;t<VE.size();t++)
    	{
    		ban[VE[t]]=1;tim=tp=scccnt=0;
    		for(int i=0;i<G.size();i++)dfn[G[i]]=0;
    		dfs(G[0],0);
    		ban[VE[t]]=0;
    		if(G.size()-E.size()+scccnt==0){ID=t;break;}
    	}
    	ban[VE[ID]]=1;tim=tp=scccnt=0;
    	for(int i=0;i<G.size();i++)dfn[G[i]]=0;
    	solve(e[E[VE[ID]-1]].u,0);
    	int ans=1,tmp=0;
    	for(int i=1;i<=scccnt;i++)if(scc[i].size()>1)ans=1ll*ans*scc[i].size()%MOD,tmp+=scc[i].size();
    	
    	sum=1ll*Pd*ans%MOD*(E.size()-tmp)%MOD;
    	
    	for(int i=1;i<=scccnt;i++)if(scc[i].size()>1)
    	{
    		int d1=P[i],d2=scc[i].size()-P[i];
    		sum=(sum+1ll*Pd*ans%MOD*d1%MOD*d2%MOD*ksm(scc[i].size(),MOD-2))%MOD;
    	}
    	printf("%d
    ",sum);
    }
    

  • 相关阅读:
    好的开源项目汇总
    强制SVN上传代码时添加日志
    微信开发-回调模式
    Struct2中自定义的Filter无效
    Ajax 传包含集合的JSON
    PostgreSQL数据库PL/PGSQL学习使用
    单用户对比PG 9.5.4和SYBASE 15.7对超大表的操作性能
    一场一波三折的SQL优化经历
    聚簇索引对数据插入的影响
    磁盘IO初探
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13204704.html
Copyright © 2011-2022 走看看