其实挺简单的但是没想出来…………

首先判断无解情况,即,一开始的图就不是仙人掌,使用tarjan判断如果一个点dfs下去有超过一个点比他早,则说明存在非简单环。

然后考虑dp,显然原图中已经属于某个简单环的边就是没用的,tarjan缩点之后删掉两个端点在一个强连通分量中的边。(无向图的tarjan要记录father防止往回走,instack数组不需要了。

现在图变成了一个森林。

然后设sum为某个点的子树个数,w[i]为i棵子树相互连成环的方案数,w[i]=w[i-1]+w[i-2]*(i-1);g[i]为第i个点(i不是根)的方案数,g[u]=f[u]*w[sum]+f[u]*w[sum-1]*sum;f[i]为第i个点(i是根)的方案数f[u]=f[u]*w[sum]

依次树形dp,把答案乘起来即可。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=500005,mod=998244353;
int T,n,m,h[N],cnt,f[N],w[N],g[N],dfn[N],tot,low[N],bl[N],col,s[N],top;
bool v[N],fl;
long long ans;
struct qwe
{
int ne,to;
}e[N*10];
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
void add(int u,int v)
{
cnt++;
e[cnt].ne=h[u];
e[cnt].to=v;
h[u]=cnt;
}
void tarjan(int u,int fa)
{
dfn[u]=low[u]=++tot;
s[++top]=u;
bool flag=0;
for(int i=h[u];i;i=e[i].ne)
if(e[i].to!=fa)
{
if(!dfn[e[i].to])
{
tarjan(e[i].to,u);
low[u]=min(low[u],low[e[i].to]);
if(low[e[i].to]<dfn[u])
{
if(flag)
{
fl=0;
return;
}
flag=1;
}
}
else
{
low[u]=min(low[u],dfn[e[i].to]);
if(dfn[e[i].to]<dfn[u])
{
if(flag)
{
fl=0;
return;
}
flag=1;
}
}
}
if(dfn[u]==low[u])
{
while(1)
{
bl[s[top--]]=u;
if(s[top+1]==u)
break;
}
}
}
void dp(int u,int fa)
{//cout<<u<<endl;
v[u]=1,f[u]=1;g[u]=0;
int sum=0;
for(int i=h[u];i;i=e[i].ne)
if(bl[u]!=bl[e[i].to]&&e[i].to!=fa)
{
dp(e[i].to,u);
f[u]=1ll*f[u]*g[e[i].to]%mod;
sum++;
}
g[u]=(1ll*f[u]*w[sum]%mod+1ll*f[u]*w[sum-1]%mod*sum%mod)%mod;
f[u]=1ll*f[u]*w[sum]%mod;
}
int main()
{
T=read();
w[0]=1,w[1]=1,w[2]=2;
for(int i=3;i<=500000;i++)
w[i]=(w[i-1]+1ll*w[i-2]*(i-1)%mod)%mod;
while(T--)
{
cnt=0;ans=1;tot=0;fl=1;top=0;
n=read(),m=read();
for(int i=1;i<=n;i++)//比memset快5倍!!
v[i]=0,h[i]=0,bl[i]=0,dfn[i]=0;
for(int i=1;i<=m;i++)
{
int u=read(),y=read();
add(u,y);add(y,u);
}
tarjan(1,0);//cout<<"OK"<<endl;
if(!fl)
{
puts("0");
continue;
}
for(int i=1;i<=n;i++)
if(!v[i])
{
dp(i,0);
ans=ans*f[i]%mod;
}
printf("%lld\n",ans);
}
return 0;
}

bzoj 4784: [Zjoi2017]仙人掌【tarjan+树形dp】的更多相关文章

  1. Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF980F.html 题目传送门 - CF980F 题意 给定一个 $n$ 个节点 $m$ 条长为 $1$ 的边 ...

  2. LOJ2250 [ZJOI2017] 仙人掌【树形DP】【DFS树】

    题目分析: 不难注意到仙人掌边可以删掉.在森林中考虑树形DP. 题目中说边不能重复,但我们可以在结束后没覆盖的边覆盖一个重复边,不改变方案数. 接着将所有的边接到当前点,然后每两个方案可以任意拼接.然 ...

  3. BZOJ4784 ZJOI2017仙人掌(树形dp+dfs树)

    首先考虑是棵树的话怎么做.可以发现相当于在树上选择一些长度>=2的路径使其没有交,同时也就相当于用一些没有交的路径覆盖整棵树. 那么设f[i]为覆盖i子树的方案数.转移时考虑包含根的路径.注意到 ...

  4. [BZOJ 4033] [HAOI2015] T1 【树形DP】

    题目链接:BZOJ - 4033 题目分析 使用树形DP,用 f[i][j] 表示在以 i 为根的子树,有 j 个黑点的最大权值. 这个权值指的是,这个子树内部的点对间距离的贡献,以及 i 和 Fat ...

  5. [BZOJ 4455] [ZJOI 2016] 小星星 (树形dp+容斥原理+状态压缩)

    [BZOJ 4455] [ZJOI 2016] 小星星 (树形dp+容斥原理+状态压缩) 题面 给出一棵树和一个图,点数均为n,问有多少种方法把树的节点标号,使得对于树上的任意两个节点u,v,若树上u ...

  6. bzoj 2427 软件安装 - Tarjan - 树形动态规划

    题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...

  7. Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装

    [洛谷P2515][HAOI2010]软件安装 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得 ...

  8. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  9. BZOJ 2435 道路修建 NOI2011 树形DP

    一看到这道题觉得很水,打了递归树形DP后RE了一组,后来发现必须非递归(BFS) 递归版本84分: #include<cstdio> #include<cstring> #in ...

随机推荐

  1. poj3532求生成树中最大权与最小权只差最小的生成树+hoj1598俩个点之间的最大权与最小权只差最小的路经。

    该题是最小生成树问题变通活用,表示自己开始没有想到该算法:先将所有边按权重排序,然后枚举最小边,求最小生成树(一个简单图的最小生成树的最大权是所有生成树中最大权最小的,这个容易理解,所以每次取最小边, ...

  2. 收集的一些Redis操作技巧教程

    redis(1).redis入门 redis(2).redis数据类型 redis(3).基于jedis.spring-data-redis 连接操作redis redis(4).基于redis 构建 ...

  3. 共享内存mmap学习 及与 shmxxx操作的区别

    上一篇学习了共享内存: http://www.cnblogs.com/charlesblc/p/6142139.html 根据这个 http://blog.chinaunix.net/uid-2633 ...

  4. 如何扩展ArcGIS中的元数据编辑器

    http://www.esrichina-bj.cn/old../library/arcnews16/Metadata.htm http://www.esrichina-bj.cn/old../lib ...

  5. 弄技术要弄通-公司reis的pub/sub怎么使用的呢?

    Pub/Sub in Redis using PHP Posted on November 14, 2011by xmeng I would like to put an example togeth ...

  6. day5-WordCount

    1.   wordcount示例开发 1.1. wordcount程序整体运行流程示意图 map阶段: 将每一行文本数据变成<单词,1>这样的kv数据 reduce阶段:将相同单词的一组k ...

  7. springMVC4(16)拦截器解析与登陆拦截模拟

    在SpringMVC中,我们会常常使用到拦截器,尽管SpringAOP也能帮我们实现强大的拦截器功能,但在Web资源供给上.却没有SpringMVC来得方便快捷. 使用SpringMVC拦截器的核心应 ...

  8. Bootstrap的js插件之弹出框(popover)

    data-toggle="popover"--使弹出框可以切换状态: title--设置弹出框的标题: data-content--设置弹出框的内容部分: data-placeme ...

  9. Windows驱动程序开发基础(四)驱动的编译调试和安装

    Windows驱动程序开发基础,转载标明出处:http://blog.csdn.net/ikerpeng/article/details/38793995 以下说一下开发出来驱动程序以后怎样编译.一般 ...

  10. 【Linux编程】进程终止和exit函数

    内核要运行一个应用程序,唯一的途径是通过系统调用.exec函数.exec又会调用启动程序,启动程序(一般是汇编语言)以类似以下的方式调用main函数: void exit(main(argc, arg ...