当前位置: 首页 > news >正文

P11363 [NOIP2024] 树的遍历

做了 4h 才做完,交上去还 T 了一发,没救了。

题意

给一棵树,用这棵树建立一张新图 \(G\),树上的每条边变成 \(G\) 的一个节点,边 \((u,v)\) 存在当且仅当 \(u\)\(v\) 在树上对应的边有公共端点,再给定若干关键点,求 \(G\) 有多少棵生成树 \(T\),满足存在一个关键边,使得从它开始搜出来的 DFS 生成树可以是 \(T\)\(n\le10^5\)

题解

显然链的情况答案为 \(1\)

菊花的情况,\(G\)\(K_{n-1}\),生成树一定是一条链,方案数为 \((n-3)!(\binom {n-1}2-\binom{n-1-k}2)\),即链的端点至少有一个是关键边。

因此原树上的每个点 \(i\)\(G\) 上都对应一个 \(K_{deg_i}\),对于 \(k=1\) 的情况方案数为 \(\prod(deg_i-1)!\),即遍历每个 \(K_{deg_i}\) 的 DFS 生成树一定是一条链,链的一个端点需要是 \(e_1\) 过来的那个点,另一个端点任取。

于是考虑在原树上做树形 DP,令 \(f_x\) 表示从 \((x,fa_x)\) 开始 DFS \(G\)\(x\) 子树内的部分,形成的 DFS 生成树个数,\(g_x\) 表示关键边在 \(x\) 子树内,或者是 \((x,fa_x)\),DFS \(G\)\(x\) 子树内的部分,形成的 DFS 生成树个数。

\(f\) 的转移是容易的,类似 \(k=1\)

\[f_x=(deg_x-2)!\prod_vf_v \]

考虑 \(g\) 的转移。容易想到枚举关键点所在的子树,但这样会在 \(x\) 的链以两个 \((x,son)\) 为端点,且这两个 \(son\) 子树内的生成树都可以从子树内的关键点出发时算重。于是令 \(h_x\) 表示关键边在 \(x\) 子树内,或者是 \((x,fa_x)\),且得到的生成树也可以是从 \((x,fa_x)\) 出发搜出来的,这样的生成树个数。考虑链的端点,有:

\[h_x=\begin{cases} (deg_x-2)!\sum_vh_v\prod_{i\neq v}f_i&(x,fa_x)\notin e\\ f_x&(x,fa_x)\in e \end{cases} \]

此时再考虑 \(g\) 的转移,容斥掉上面所说的算重的部分,并且当关键边是 \((x,fa_x)\) 时需要加上从 \((x,fa_x)\) 出发,且未被算过的部分:

\[g_x=(deg_x-1)!\sum_vg_v\prod_{i\neq v}f_i-(deg_x-2)!\sum_{u<v}h_uh_v\prod_{i\neq u,i\neq v}f_i+[(x,fa_x)\in e](f_x-h_x) \]

统计答案时,找到一个叶子 \(x\),令 \((x,fa_x)\) 为根即可。

前缀和优化一下可以做到 \(O(n\log V)\),其中 \(\log V\) 是求逆元的复杂度。

实现

#include <iostream>
#define int long long
const int N=2e5+5,mod=1e9+7;
int n,K,a[N],p[N],f[N],g[N],h[N],del[N],fa[N],b[N];
std::basic_string<int> G[N];
struct Edge {int u,v;} e[N];
int qpow(int x,int y) {int r=1;for(;y;y>>=1,x=x*x%mod) if(y&1) r=r*x%mod;return r;}
void dfs0(int x,int fa)
{::fa[x]=fa;for(int v:G[x]) if(v!=fa) dfs0(v,x);
}
void dfs(int x,int fa)
{int son=G[x].size()-1,prd=1;for(int v:G[x]) if(v!=fa) dfs(v,x),prd=prd*f[v]%mod;for(int v:G[x]) if(v!=fa) del[v]=qpow(f[v],mod-2);f[x]=p[son]*prd%mod,g[x]=h[x]=0;if(son){for(int v:G[x]) if(v!=fa){(h[x]+=h[v]*prd%mod*del[v])%=mod;(g[x]+=g[v]*prd%mod*del[v])%=mod;}h[x]=h[x]*p[son-1]%mod;g[x]=g[x]*p[son]%mod;}if(son>1){int tmp=0,pre=0;for(int v:G[x]) if(v!=fa)(tmp+=pre*h[v]%mod*del[v]%mod*prd)%=mod,(pre+=h[v]*del[v])%=mod;(g[x]-=tmp*p[son-1])%=mod;}if(b[x]) (g[x]+=f[x]-h[x])%=mod,h[x]=f[x];
}
void neatisaac()
{for(int i=1;i<=n;i++) G[i].clear(),b[i]=0;std::cin>>n>>K;for(int i=1,u,v;i<n;i++) std::cin>>u>>v,G[u]+=v,G[v]+=u,e[i]={u,v};for(int i=1;i<=K;i++) std::cin>>a[i];for(int i=1;i<=n;i++) if(G[i].size()==1){dfs0(i,0);for(int j=1;j<=K;j++)fa[e[a[j]].u]==e[a[j]].v?b[e[a[j]].u]=1:b[e[a[j]].v]=1;dfs(G[i][0],i),std::cout<<(g[G[i][0]]+mod)%mod<<'\n';return;}
}
signed main()
{std::cin.tie(0)->sync_with_stdio(0);int c,T;std::cin>>c>>T;p[0]=1;for(int i=1;i<N;i++) p[i]=p[i-1]*i%mod;while(T--) neatisaac();
}
http://www.jsqmd.com/news/925761/

相关文章:

  • 改图片尺寸工具入门指南,新手使用调整大小实用攻略 - 软件工具教程方法
  • 架构演进之路:从单体到云原生的技术变革
  • 【Gemini系统维护权威指南】:20年SRE亲授3大避坑法则与5分钟应急响应流程
  • 从一次GCC编译崩溃,我搞懂了Linux的ulimit和文件描述符到底怎么管
  • 照片改 JPG 入门指南,解决上传格式不符实用转换攻略 - 软件工具教程方法
  • Gemini vs DeepL vs 標準和訳AI:237句NHK新闻实测对比(含假名转换错误率、长复合句断句准确率、汉字简繁映射偏差)
  • 国内主流数字教材软件排行 适配教学全场景需求 - 互联网科技品牌测评
  • 在线去本地视频水印的工具推荐:三步搞定本地视频素材处理 - 工具软件使用方法推荐
  • 别再傻傻重启电脑了!Windows下用netstat和taskkill一键清理端口占用的保姆级教程
  • Gemini跨境数据流架构设计(Google官方未公开的5层加密路由模型)
  • git分支合并的切换逻辑详解
  • 【2025视频生产力革命倒计时】:3类不可逆技术跃迁正在发生,你的团队还停留在Sora 1.0思维?
  • Gemini情感分析API调用全解析:从零配置到毫秒级响应的7步标准化流程
  • Gemini广告创意策划速成课:1个框架、6个变量、12小时上线首条达标素材(附可执行Checklist)
  • 国内主流AI课件生成软件实测排行与选型指南 - 互联网科技品牌测评
  • 制作照片水印必备工具,主流软件和免费小程序盘点汇总 - 软件工具教程方法
  • 如何在Windows上实现系统级Steam控制器支持:3步终极完整指南
  • 新手用 IDEA 做 Java 贪吃蛇期末大作业完整心路历程
  • 免费在线图片改尺寸小程序,裁剪缩放一体图片工具 - 软件工具教程方法
  • ctf show web 入门66
  • 【Gemini股东大会机密简报】:2024年战略转向、AI伦理红线与股东投票权变更的3大未公开细节
  • 从日均500万条丢推到SLA 99.99%,我们重构Gemini通知管道的7个关键决策,含MQ选型对比、幂等ID生成器与灰度发布Checklist
  • 为什么你的Gemini翻译在波兰语场景下F1值骤降41%?——欧洲语言形态学适配失效根因分析与补丁级修复
  • 618 大促!Mac 平台知名视频下载工具 Downie 4 限时 6 折,买断仅需 59.4 元
  • 告别单调地图!用QGIS的‘分级渲染’功能,5分钟让你的降雨量数据‘开口说话’
  • DLSS Swapper终极指南:3步搞定游戏DLSS智能管理,帧率飙升不是梦
  • 3大核心技术突破:Anno 1800 Mod Loader如何彻底改变游戏模组开发体验
  • 【非营利组织紧急通告】:Gemini捐赠活动策划窗口期仅剩17天——错过本轮算法适配将损失43%潜在捐赠额
  • 豆包即梦图片水印如何去除?实测横评 - 工具软件使用方法推荐
  • 第一章 Qt 概述_csdn