题目

给定一个简单无向连通图,问有多少种加边方案使得这个图变成简单仙人掌。


分析

首先找到一棵生成树,考虑其它非树边所对应的树的路径上的边最多只能用一次,

这可以用树上差分做,如果一个点到其父节点的边被用了多次就一定无解。

否则没有被用过的部分将形成若干棵树,方案就是它们的乘积。

等于说问用若干条路径覆盖一棵树的方案。

设 \(dp[x]\) 表示以 \(x\) 为根的子树的方案数。

只需要考虑 \(x\) 的邻边如何连接,子树的答案直接相乘。

设 \(f[n]\) 表示 \(n\) 条边任意匹配的方案数,则

\(f[n]=f[n-2]*(n-1)+f[n-1]\)

那么 \(dp[x]*=f[deg[x]]\)


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=500011,mod=998244353; struct node{int y,next;}e[N<<1],E[N<<1];
int f[N],c[N],v[N],as[N],hs[N],et=1,Et=1,n,dp[N],ans,fat[N],g[N],flag,upd,Lca[N<<1];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
inline void Clear(){
for (rr int i=1;i<=n;++i) c[i]=as[i]=hs[i]=0;
}
inline void dfs1(int x,int fa){
f[x]=x,v[x]=upd,fat[x]=fa;
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa) dfs1(e[i].y,x),f[e[i].y]=x;
for (rr int i=hs[x];i;i=E[i].next)
if (v[E[i].y]==upd) Lca[i]=Lca[i^1]=getf(E[i].y);
}
inline void dfs2(int x,int fa){
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa) dfs2(e[i].y,x),c[x]+=c[e[i].y];
}
inline void dfs3(int x,int TOP){
rr int sub=0; dp[x]=1;
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fat[x]){
if (!c[e[i].y]) dfs3(e[i].y,TOP),++sub,dp[x]=1ll*dp[x]*dp[e[i].y]%mod;
else dfs3(e[i].y,e[i].y);
}
if (x==TOP) ans=1ll*ans*dp[x]%mod*g[sub]%mod;
else dp[x]=1ll*dp[x]*g[sub+1]%mod;
}
signed main(){
g[0]=g[1]=1;
for (rr int i=2;i<N;++i) g[i]=(g[i-2]*(i-1ll)+g[i-1])%mod;
for (rr int T=iut();T;--T,putchar(10)){
n=iut(),et=Et=ans=flag=1,++upd;
for (rr int i=1;i<=n;++i) f[i]=i;
for (rr int TOT=iut();TOT;--TOT){
rr int x=iut(),y=iut();
if (getf(x)!=getf(y)){
rr int fa=getf(x),fb=getf(y);
if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
f[fa]=fb;
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}else{
E[++Et]=(node){y,hs[x]},hs[x]=Et;
E[++Et]=(node){x,hs[y]},hs[y]=Et;
}
}
dfs1(1,0);
for (rr int i=2;i<=Et;i+=2)
++c[E[i].y],++c[E[i^1].y],c[Lca[i]]-=2;
dfs2(1,0);
for (rr int i=1;i<=n&&flag;++i)
if (c[i]>1) putchar(48),flag=0;
if (!flag) {Clear(); continue;}
dfs3(1,1),print(ans),Clear();
}
return 0;
}

#树形dp#洛谷 3687 [ZJOI2017]仙人掌的更多相关文章

  1. ●洛谷P3687 [ZJOI2017]仙人掌

    题链: https://www.luogu.org/problemnew/show/P3687题解: 计数DP,树形DP. (首先对于这个图来说,如果初始就不是仙人掌,那么就直接输出0) 然后由于本来 ...

  2. 树形DP 洛谷P2014 选课

    洛谷P2014 选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门 ...

  3. 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告

    P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...

  4. 洛谷P4244 [SHOI2008]仙人掌图 II

    传送门 首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径. 那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并 ...

  5. 区间DP 洛谷P2858牛奶零食

    题目链接 题意:你有n个货物从1-n依次排列,每天可以从两侧选一个出来卖,卖的价格是当天的天数乘该货物的初始价格,问这批货物卖完的最大价格 输入:第一行n,之后是n个货物的初始价值 这道题不能用贪心做 ...

  6. P1279 字串距离 dp 洛谷

    题目描述 设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□”和“abcb□cd□”都是X ...

  7. dp 洛谷P1977 出租车拼车 线性dp

    题目背景 话说小 x 有一次去参加比赛,虽然学校离比赛地点不太远,但小 x 还是想坐 出租车去.大学城的出租车总是比较另类,有“拼车”一说,也就是说,你一个人 坐车去,还是一堆人一起,总共需要支付的钱 ...

  8. 经典DP 洛谷p1880 石子合并

    https://www.luogu.org/problemnew/show/P1880 题目 题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新 ...

  9. [DP]洛谷P1115最大子段和

    题目来源 https://www.luogu.org/problemnew/show/P1115 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入输出格式 输入格式: 第一行是一 ...

  10. 尼克的任务 dp 洛谷1280

    蒟蒻表示老久没看过dp题目了,,挺水的一道dp题目都没想出来,,, 首先设dp[i]表示从开始到i时间的最大空闲时间,用vector to[x] 表示从x点开始的任务结束时间,cnt[x]表示从x开始 ...

随机推荐

  1. pikachu sql inject delete 注入

    留言板输入几条信息 出现删除按钮,点他 通过burpsuite拦截请求,请求报文如下 GET /vul/sqli/sqli_del.php?id=57 HTTP/1.1 Host: 192.168.1 ...

  2. pymysql基本语法,sql注入攻击,python操作pymysql,数据库导入导出及恢复数据---day38

    1.pymysql基本语法 # ### python操作mysql import pymysql ''' # ### 1.基本语法 #(1) 创建连接 host user password datab ...

  3. 亲测可行,Android Studio 查看源码出现 Source for ‘Android API xxx Platform’ not found 的解决方法

    亲测可行,Android Studio 查看源码出现 Source for 'Android API xxx Platform' not found 的解决方法 如标题中的问题,产生的原因就是 SDK ...

  4. Emqx高可用架构

    目录 优化前架构 主要问题 haproxy问题 优化后架构 优化功能点 emq版本升级 linux系统调优 haproxy调优 测试工具 依赖安装 配置erl环境变量 安装压测软件 测试指令与结果展示 ...

  5. 【Azure 应用服务】遇见“无法创建hybrid connection for App Service”的解决办法

    Hybrid Connection (混合连接) 在两个联网应用程序之间启用了双向.请求-响应和二进制流通信以及简单的数据报流.通过混合连接,可以实现应用部署在公网环境中,而数据库保存在本地私网环境中 ...

  6. 【Azure 存储服务】Azure Blob上传大文件(600MB)出现内存溢出情况(Java SDK)

    问题描述 Java 云端开发,调用 blob 上传会产生内存溢出,Java上调用的方式如下: InputStream inputStream = new BufferedInputStream(new ...

  7. 【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?

    问题描述 如何查看App Service Java堆栈JVM相关的参数默认配置值? 问题解答 可以通过App Service的高级管理工具(kudu:)来查看JVM的相关参数,使用命令:java -X ...

  8. 【Azure 应用服务】App Service多个部署槽(Slot)之间,设置Traffic百分比后,如何来判断请求是由那一个槽(Slot)来进行处理呢?

    问题描述 当我们部署应用到App Service后,为了实现对生成的最小影响,通常是把新版本部署在一个预生产的槽中,然后进行验证.另一方面,为了进行A/B验证,需要把生成槽的流量,切入一部分到预生产槽 ...

  9. confluence 破解系列

    confluence 破解系列 目录 confluence 破解系列 前言 confluence 一. 安装数据库mysql 二 docker启动confluence 前言 confluence Co ...

  10. mainWindow = new BrowserWindow 打开慢的原因 electron 已解决 Windows Defender 拦截导致

    Windows Defender 导致拦截 不是变量的事儿 解决方案: win10 开始 设置 - windows 安全中心 - 病毒和威胁防护 - 病毒和威胁防护设置 - 排除项 - 添加排除项 将 ...