初三年后集训测试 $T 3 $ 树上的宝藏

$$HZOI$$


·题意

· \(Description\)

蒜头君有一棵 \(n\) 个节点的树(即 \(n\) 个节点, \(n−1\) 条边的无向连通图)。树的每个节点上都有一个宝藏。蒜头君准备大动干戈,拿到这些保证。

但是在拿宝藏之前,蒜头君发现了一个问题,由于树的边的材质问题,若两个节点被一条边直接连接,为了确保安全,那么这两个节点上的宝藏最多可以拿一个。

好在同样擅长化学的巨佬--花椰妹给了蒜头君一条特殊材质的边。蒜头君可以选定一条边并将这条边的材质替换成特殊材质的边,于是为了确保安全,被这条选定的边直接相连的两个节点上的宝藏最少拿一个。

蒜头君想知道,对于每一条边,若选定这条边替换成花椰妹送给他的特殊材质的边,在确保安全的情况下,有多少种拿的方法是可行的。

· \(Input\)

第一行一个正整数 \(n\) 。

后面 \(n−1\) 行,第 \(i\) 行有每行两个正整数 \(u\) , \(v\) 代表第 \(i−1\) 条边连接着点 \(u\) 和点 \(v\) 。

· \(Output\)

\(n-1\) 行 , 每行一个数,代表此边为特殊边时的方案数,输出的是对 \(998244353\) 取模的余数 。


·题解


·分析

其实换根还是很好想的。

先不考虑特殊边。

先定义一个 \(dp\) 表示在以 \(1\) 为根的情况下,以 \(i\) 为根的子树的方案数。

\(dp\) 开两维,第一维是 \(i\) , 第二维是 $ 0 || 1 $ , \(0\) 代表此位置选 \(0\) , \(1\) 同上。

易得出:

\[dp[ \ i \ ][ \ 0 \ ] \times = ( dp[ \ j \ ][ \ 0 \ ] + dp[ \ j \ ][ \ 1 \ ] ) ;
\]
\[dp[ \ i \ ][ \ 1 \ ] \times = dp[ \ j \ ][ \ 0 \ ]
\]

然后我们在定义一个定义方式与 \(dp\) 相同的 \(f\) 数组 , 表示以 \(i\) 为根的整棵树的方案数。

定义前驱结点即后继节点的直系父亲 \(x\), 后继节点即儿子 \(y\).

我们假设(或可以看做已知)你已知 \(f_{x,0 \ and \ 1}\) ,因为你是要打 \(DFS\) 的, 那么我们可以在进这一遍递归之前求出之。

那么, $$ f_{ y , 1 } = \frac{ f_{x,0} }{ dp_{y,1}+dp_{y,0}} \times dp_{y,1}$$

\[f_{ y , 0 } = \left( \frac{ f_{x , 1}}{dp_{y,0}} + \frac{f_{ x , 0 } }{dp_{y,1} + dp_{y,0} } \right) \times dp_{y,0}
\]

解释一下:

在你已知 \(x\) 是根的情况下,当 \(y\) 要取 \(1\) 时,由于一条边上至多选一个点,因此 \(x\) 取 \(0\) ;

当 \(x\) 取 \(0\) 时看上面 \(dp\) 数组的式子,你要求无 \(y\) 的方案数再乘以 \(y\) 取零的方案数;

\(y\) 取零同上。

然后推一下当边 \(i\) 是特殊边时的时候。

这时 \(f\) 和 \(dp\) 均已知,考虑所有的情况:

\(x,y\) 分别是树根(令此特殊边为树根至其儿子的路径)

  1. \(x\) 取一, \(y\) 取一

则此时:

\[ans = \frac{f_{x,1}}{dp_{y,0}} \times dp_{y,1}
\]
  1. 当 \(x\) 取一, \(y\) 取零时
\[ans = \frac{f_{x,1}}{dp_{y,0}}\times dp_{y,0}
\]

3.当 \(x\) 取零 , \(y\) 取一时

\[ans=\frac{f_{x,0}}{dp_{y,0}+dp_{y,1}} \times dp_{y,1}
\]
\[\]

· \(Code\)

点击查看代码
#include <bits/stdc++.h>
#define qcin cin
#define qcout cout
#define int long long
using namespace std ;
const int N = 3e5 + 10 ;
const int mod = 998244353 ;
int dp[ N ][ 2 ] , f[ N ][ 2 ] ;
int head[ N ] , cnt , n ;
int father[ N ] ;
class node
{
public :
int xe , ye ;
}pe[ N ] ;
class edge
{
public:
int next , to ;
}e[ N ] ;
int Quick_Pow( int alpha , int beta )
{
int ans = 1 ;
while ( beta > 0 )
{
if( beta & 1 ) ans = ( ans * alpha ) % mod ;
beta >>= 1 ;
alpha = ( alpha * alpha ) % mod ;
}
return ans ;
}
int inv( int alpha )
{
return ( Quick_Pow( alpha , mod - 2 ) ) ;
}
inline void add( int x , int y )
{
cnt ++ ;
e[ cnt ].to = y ;
e[ cnt ].next = head[ x ] ;
head[ x ] = cnt ;
}
void dfs1( int x , int fa )
{
dp[ x ][ 0 ] = dp[ x ][ 1 ] = 1 ;
for ( int i = head[ x ] ; i ; i = e[ i ].next )
{
int y = e[ i ].to ;
if( y != fa )
{
father[ y ] = x ;
dfs1( y , x ) ;
dp[ x ][ 0 ] = ( dp[ x ][ 0 ] * ( dp[ y ][ 0 ] + dp[ y ][ 1 ] ) ) % mod ;
dp[ x ][ 1 ] = ( dp[ y ][ 0 ] * dp[ x ][ 1 ] ) % mod ;
}
}
}
void dfs2( int x , int fa )
{
for ( int i = head[ x ] ; i ; i = e[ i ].next )
{
int y = e[ i ].to ;
if( y != fa )
{
f[ y ][ 1 ] = f[ y ][ 0 ] = 1 ;
int inver0 = inv( dp[ y ][ 0 ] ) , inver1 = inv( dp[ y ][ 1 ] + dp[ y ][ 0 ] ) ;
int bemod1 = ( ( f[ x ][ 1 ] ) * ( inver0 ) ) % mod ;
int bemod2 = ( f[ x ][ 0 ] * ( inver1 ) ) % mod ;
f[ y ][ 1 ] = ( dp[ y ][ 1 ] * bemod2 ) % mod ;
f[ y ][ 0 ] = ( dp[ y ][ 0 ] * ( bemod1 + bemod2 ) ) % mod ;
dfs2( y , x ) ;
}
}
}
inline void Check_Shadow( int x , int y )
{
int inv_y_0 , inv_y_1 , inv_y_01 ;
inv_y_0 = inv( dp[ y ][ 0 ] ) ;
inv_y_1 = inv( dp[ y ][ 1 ] ) ;
inv_y_01 = inv( dp[ y ][ 1 ] + dp[ y ][ 0 ] ) ;
int ans = 0 ;
ans = ( ans + ( ( ( f[ x ][ 1 ] * inv_y_0 ) % mod ) * dp[ y ][ 1 ] ) % mod ) ;
ans = ( ans + ( ( ( f[ x ][ 0 ] * inv_y_01 ) % mod ) * dp[ y ][ 1 ] ) % mod ) ;
ans = ( ans + f[ x ][ 1 ] ) % mod ;
cout << ans << '\n' ;
}
signed main( )
{
#ifndef ONLINE_JUDGE
freopen( "1.in" , "r" , stdin ) ;
freopen( "1.out" , "w" , stdout ) ;
#endif
cin >> n ;
int x , y ;
for ( int i = 1 ; i < n ; ++ i )
{
cin >> x >> y ;
pe[ i ].xe = x ;
pe[ i ].ye = y ;
add( x , y ) ; add( y , x ) ;
}
int roo = 1 ;
dfs1( roo , 0 ) ;
f[ 1 ][ 1 ] = dp[ 1 ][ 1 ] ;
f[ 1 ][ 0 ] = dp[ 1 ][ 0 ] ;
dfs2( 1 , 0 ) ;
for ( int i = 1 ; i < n ; ++ i )
{
if( father[ pe[ i ].ye ] != pe[ i ].xe )
{
swap( pe[ i ].xe , pe[ i ].ye ) ;
}
Check_Shadow( pe[ i ].xe , pe[ i ].ye ) ;
}
}

· 结尾撒花 \(\color{pink}✿✿ヽ(°▽°)ノ✿\)

初三年后集训测试T3---树上的宝藏的更多相关文章

  1. noip2019集训测试赛(二十一)Problem B: 红蓝树

    noip2019集训测试赛(二十一)Problem B: 红蓝树 Description 有一棵N个点,顶点标号为1到N的树.N−1条边中的第i条边连接顶点ai和bi.每条边在初始时被染成蓝色.高桥君 ...

  2. FJ省队集训最终测试 T3

    思路:状态压缩dp,f[i][j[[k]代表i行j列这个格子,连续的状态为k,这个连续的状态是什么?就是下图 X格子代表我当前走到的地方,而这里的状态就是红色部分,也就是连续的一段n的状态,我们是分每 ...

  3. [2016北京集训测试赛15]statement-[线段树+拆环]

    Description Solution 由于题目要求,将a[i]->b[i](边权为i)后所得的图应该是由森林和环套树组合而成. 假如是树形结构,所有的t[i]就直接在线段树t[i]点的dfs ...

  4. 安徽师大附中%你赛day5 T3 树上行走 解题报告

    树上行走 题目背景 \(\mathrm{Smart}\) 的脑洞非常大, 经常幻想出一些奇怪的东西. 题目描述 某一天,\(\mathrm{Smart}\) 幻想出了一棵没有边际的二叉树,脑补着在那棵 ...

  5. noip2017集训测试赛(十一)Problem C: 循环移位

    题面 Description 给定一个字符串 ss .现在问你有多少个本质不同的 ss 的子串 t=t1t2⋯tm(m>0)t=t1t2⋯tm(m>0) 使得将 tt 循环左移一位后变成的 ...

  6. noip2017集训测试赛(三)Problem C: MST

    题面 Description 给定一个n个点m条边的连通图,保证没有自环和重边.对于每条边求出,在其他边权值不变的情况下,它能取的最大权值,使得这条边在连通图的所有最小生成树上.假如最大权值为无限大, ...

  7. 2016集训测试赛(十九)Problem C: 无聊的字符串

    Solution 傻X题 我的方法是建立后缀后缀树, 然后在DFS序列上直接二分即可. 关键在于如何得到后缀树上每个字符对应的字节点: 我们要在后缀自动机上记录每个点在后缀树上对应的字母. 考虑如何实 ...

  8. BZOJ 4543 2016北京集训测试赛(二)Problem B: thr 既 长链剖分学习笔记

    Solution 这题的解法很妙啊... 考虑这三个点可能的形态: 令它们的重心为距离到这三个点都相同的节点, 则其中两个点分别在重心的两棵子树中, 且到重心的距离相等; 第三个点可能在重心的一棵不同 ...

  9. 2016北京集训测试赛(八)Problem C: 直径

    Solution 一个定理: 把两棵树用一条边练成一棵树后, 树的直径在原来两棵树的四个直径端点中产生. 放到这一题, 我们通过DP先求出大树中以每个点为根的子树中的直径, 再取每棵小树中与其他树有连 ...

  10. 2017省选集训测试赛(二十五)Problem B recollection

    @(XSY)[后缀数组, 启发式合并, ST表] Description Solution 后缀数组 + 启发式合并 + Sparse Table. 这是第一次写树上后缀数组. 对以每个点为根的子树统 ...

随机推荐

  1. QT学习:06 常用的全局变量与宏定义

    --- title: framework-cpp-qt-06-常用的全局变量与宏定义 EntryName: framework-cpp-qt-06-global date: 2020-04-10 11 ...

  2. 2.上传hdfs系统:将logs目录下的日志文件每隔十分钟上传一次 要求:上传后的文件名修为:2017111513xx.log_copy

    先在hdfs系统创建文件夹logshadoop fs -mkdir /logs 编辑shell脚本 filemv.sh #!/bin/bashPATH=/usr/local/bin:/bin:/usr ...

  3. python3 webssh

    简介 webssh 是 一个简单的 Web 应用程序,用作 ssh 客户端来连接到 ssh 服务器.它是用Python编写的,基于tornado.paramiko和xterm.js.下面简单搭建一个网 ...

  4. Mybatis 中 foreach 的四种用法

    foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. ...

  5. 树莓派4B-PCA9685驱动舵机

    前言 不知道你们有没有遇到过这么一种情况,直接用树莓派的引脚输出PWM控制舵机,舵机是会出现抖动的.就算代码进行一定的时延迟优化还是会有影响的. 现在我们可以使用PCA9685这个模块去驱动舵机. P ...

  6. ComfyUI进阶篇:ComfyUI核心节点(四)

    ComfyUI核心节点(四) 前言: 学习ComfyUI是一场持久战.当你掌握了ComfyUI的安装和运行之后,会发现大量五花八门的节点.面对各种各样的工作流和复杂的节点种类,可能会让人感到不知所措. ...

  7. 虚拟 DOM 实现原理?

    虚拟 DOM 的实现原理主要包括以下 3 部分: 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象: diff 算法 - 比较两棵虚拟 DOM 树的差异: pach 算法 ...

  8. 1.Javascript 快速入门(主要)

    运算 &&运算是与运算,只有所有都为true,&&运算结果才是true: true && true; // 这个&&语句计算结果为tru ...

  9. 《探索Python Requests中的代理应用与实践》

    requests加代理 高匿API代理 此处使用的小象代理:1元100个,便宜,可以购买尝试加下代理 存活期1到2分钟 import time import requests from lxml im ...

  10. 全网最适合入门的面向对象编程教程:12 类和对象的Python实现-Python使用logging模块输出程序运行日志

    全网最适合入门的面向对象编程教程:12 类和对象的 Python 实现-Python 使用 logging 模块输出程序运行日志 摘要: 本文主要介绍了日志的定义和作用,以及 Python 内置日志处 ...