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

    给出一个图,满足删掉其中一条边之后可以变成一棵仙人掌。问生成树个数。

    (n,mle 10^5)


    传统做法:可以感受到图应该是一个大环串着多个环,然后在上面接一些子仙人掌。首先找到一条边,满足删掉这条边之后变成一棵仙人掌。如果删这条边,答案为仙人掌环长乘积;如果不删这条边,对其它部分建圆方树,然后求出这条边对应两点之间路径,枚举哪个环割掉两条边,其它环割掉一条边。可以(O(n))做。(找边:先跑tarjan求出所有强联通分量,在强联通分量内求点度。边一定在存在三度点的强联通分量内。找到这个三度点,枚举三条边,分别判定)

    模板做法:广义串并联图。

    定义:不存在四个点,满足存在四个点两两之间路径的集合,使其不能在端点之外的地方相交,的无向图。

    只要广义串并联图,可以通过收缩操作,即:删1度点、缩2度点、叠合重边,最终变成一个点。(不是广义串并联图的这样操作下去显然不能变成一个点)

    可以DP。对于当前图中,(f_x,g_x)分别表示当前边对应的边形单元是联通还是不连通的方案数。

    删1度点:答案乘(f_x)

    缩2度点:(f=f_xf_y,g=g_xf_y+f_xg_y)

    叠合重边:(f=g_xf_y+f_xg_y,g=g_xg_y)

    进行收缩的时候维护一下即可。

    收缩的时候,最好能叠合重边就先叠合重边,然后再删1度点或缩2度点。否则容易出奇怪的问题。


    using namespace std;
    #include <bits/stdc++.h>
    #define N 500005
    #define fi first
    #define se second
    #define mp make_pair
    #define ll long long
    #define mo 998244353
    int n,m;
    struct edge{int u,v;int to(int z){return u^v^z;}} ed[N];
    multiset<int> nei[N];
    map<pair<int,int>,int> e;
    priority_queue<pair<int,int> > q;
    int cnt;
    ll f[N],g[N],ans;
    void era(int x){
    	int u=ed[x].u,v=ed[x].v;
    	nei[u].erase(x);
    	nei[v].erase(x);
    	if (e[mp(u,v)]==x)
    		e.erase(mp(u,v));
    }
    void ins(int x){
    	int u=ed[x].u,v=ed[x].v;
    	nei[u].insert(x);
    	nei[v].insert(x);
    	if (e.find(mp(u,v))==e.end())
    		e[mp(u,v)]=x;
    	else
    		q.push(mp(1,x));
    }
    void check(int z){
    	if (nei[z].size()==2)
    		q.push(mp(0,z));
    }
    void work(){
    	for (int i=1;i<=n;++i)
    		if (nei[i].size()<=2)
    			q.push(mp(0,i));
    	while (!q.empty()){
    		int x=q.top().fi,y=q.top().se;
    		q.pop();
    		if (x){
    			x=e[mp(ed[y].u,ed[y].v)];
    			if (x==y) continue;
    			f[x]=(f[x]*g[y]+g[x]*f[y])%mo;
    			g[x]=g[x]*g[y]%mo;
    			era(y);
    			check(ed[x].u);
    			check(ed[x].v);
    		}
    		else{
    			int z=y;
    			if (nei[z].size()==1){
    				x=*nei[z].begin();
    				ans=ans*f[x]%mo;
    				era(x);
    				check(ed[x].to(z));
    			}
    			else if (nei[z].size()==2){
    				x=*nei[z].begin(),y=*nei[z].rbegin();
    				int u=ed[x].to(z),v=ed[y].to(z);
    				g[x]=(f[x]*g[y]+g[x]*f[y])%mo;
    				f[x]=f[x]*f[y]%mo;
    				era(x);
    				era(y);
    				if (u>v) swap(u,v);
    				ed[x]={u,v};
    				ins(x);
    			}
    		}
    	}
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    	//freopen("out.txt","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=0;i<m;++i){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		if (u>v) swap(u,v);
    		ed[i]={u,v};
    		ins(i);
    	}
    	for (int i=0;i<m;++i) 
    		f[i]=g[i]=1;
    	ans=1;
    	work();
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    02.JSP内置对象
    01.JSP基础语法
    Spring第二天:Spring的IOC的注解方式、Spring的AOP开发(XML)
    Spring第一天:Spring的概述、SpringIOC入门(XML)、Spring的Bean管理、Spring属性注入
    Struts2学习第4天--拦截器
    Struts2学习第3天--OGNL、EL、值栈
    Struts2学习第2天--Struts2的Servlet的API的访问 Struts2的结果页面的配置 Struts2的数据的封装(包括复杂类型)
    Struts2学习第一天--Struts2的概述、Struts2的入门、Struts2常见的配置、Struts2的Action的编写
    Hibernate学习第4天--HQL——QBC查询详解,抓取策略优化。
    Hibernate学习第三天(2)(多对多关系映射)
  • 原文地址:https://www.cnblogs.com/jz-597/p/14819215.html
Copyright © 2011-2022 走看看