初三年后集训测试 $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. OpenTelemetry 深度定制:跨服务追踪的实战技巧

    背景 在上一篇<从 Dapper 到 OpenTelemetry:分布式追踪的演进之旅>中在最后提到在做一些 Trace 的定制开发. 到现在差不多算是完成了,可以和大家分享一下. 我们的 ...

  2. Android系统启动:2-Init篇

    Android系统启动:Init篇 原文:http://gityuan.com/2016/02/05/android-init/ 概述 init进程是Linux系统中用户空间的第一个进程,进程号固定为 ...

  3. Ubuntu访问samba共享文件

    Ubuntu访问samba共享文件 参考:https://www.cnblogs.com/Wolf-Dreams/p/11241198.html 做法 安装samba-client.cifs-util ...

  4. 高通mm-camera平台 Camera bring up基本调试思路

    原文:https://www.cnblogs.com/thjfk/p/4086001.html 确定硬件 1.首先对照原理图,检查camera module的pin脚连接是否正确. 2.用示波器量Ca ...

  5. Centos 下Rabbit MQ 常用操作指令 汇总

    1.rabbitmq 服务的启动停止. service rabbitmq-server start service rabbitmq-server stop 重启命令需要依次执行 stop 再 sta ...

  6. fpga是什么

    FPGA(Field Programmable Gate Array) 现场可编程门阵列

  7. Oracle自定义数据类型

    1 CREATE OR REPLACE FUNCTION split(p_str IN clob, 2 p_delimiter IN VARCHAR2 default (',') --分隔符,默认逗号 ...

  8. C# 判断字符串是否为整数

    /// <summary> /// 判断一个字符串是否是正整数 /// </summary> /// <param name="s"></ ...

  9. 图表绘制之RepeatNode的妙用

    图表绘制之RepeatNode的妙用 前言 最近接到许多大屏项目,其中有一个智慧大楼的项目,大致是由3d场景+数据图表组成,需要能监控实时数据.安防 监控.出入统计以及消防安全等功能如下图 但是在开发 ...

  10. njs最详细的入门手册:Nginx JavaScript Engine

    原文链接:https://hi.imzlh.top/2024/07/08.cgi 关于njs 首先,njs似乎在国内外都不受关注,资料什么的只有 官网参考手册,出了个问题只能看到Github Issu ...