首页 > 其他分享 >带修改树上随机游走到叶节点期望得分

带修改树上随机游走到叶节点期望得分

时间:2023-04-24 19:22:39浏览次数:38  
标签:得分 int dfrac sum 游走 define cases 节点 mod

太菜了,搞了一下午才搞懂。。

题意:

一棵有 \(n\) 个节点的树,每个点都有一个权值 \(a_i\)。从 \(1\) 号点开始,每次等概率随机移动到一个相邻节点 \(i\),并获得 \(a_i\) 的得分。(可以重复获得,起点权值也计算)

有 \(q\) 次修改,每次修改一个点的权值。在一开始和每次修改后,求出移动到叶节点的期望得分,对 \(998244353\) 取模。保证 \(1\) 号点不是叶子。

\(n,q\le 10^5\)

先 DP,设 \(d_u\) 为节点 \(u\) 的度数,\(to_u\) 为 \(u\) 相邻点的集合,\(f_u\) 表示从 \(u\) 开始游走,到达叶子的期望得分,则有:

\[f_u=\begin{cases} a_u&,d_u=1\\ a_u + \dfrac{\sum_{v\in to_u}f_v}{d_u}&,\text{otherwise} \end{cases}\]

看起来只能高斯消元,但我们可以指定 \(1\) 号点为根,这样每个点都有一个父亲 \(p_u\) 和所有儿子的集合 \(son_u\)。稍微给 \(f\) 变个形:

\[f_u=\begin{cases} a_u&,d_u=1\\ a_u + \dfrac{\left(f_{p_u}+\sum_{v\in son_u}f_v\right)}{d_u}&,\text{otherwise} \end{cases}\]

只需要考虑 \(d_u\neq1\) 的情况,但是依然不太好做。

考虑设主元,将 \(f_u\) 表示为 \(k_u f_{p_u} + b_u\) 的形式,显然当 \(u\) 是叶子时,\(k_u=0,\,b_u=a_u\)。

设\(K=\sum_{v\in son_u}k_v,\, B=\sum_{v\in son_u}b_v\),这样我们可以递归求出每个点的 \(k_u\) 和 \(b_u\):

\[\begin{aligned} &f_u=a_u+\dfrac{f_{p_u}+\sum_{v\in son_u}{(k_vf_u+b_v)}}{d_u}\\\\ &f_u=a_u + \dfrac{f_{p_u}+Kf_u+B}{d_u}\\\\ &\left(1-\dfrac{K}{d_u}\right) f_u=\dfrac{f_{p_u}}{d_u} + a_u + \dfrac{B}{d_u}\\\\ &f_u=\dfrac 1{d_u-K}f_{p_u} + \dfrac{d_ua_u+B}{d_u-K} \end{aligned} \]

\[\begin{cases} k_u=\dfrac 1{d_u-K}\\\\ b_u=\dfrac{d_ua_u+B}{d_u-K}=k_u\left(d_ua_u+B\right) \end{cases} \]

观察上式,考虑每个点对答案的贡献,即 \(a_u\) 被加到 \(f_1\) 上时前面的系数。我们发现,若 \(u\) 不是叶子,这个系数是 \(u\) 到 \(1\) 的路径上所有点的 \(k\) 的积再乘以 \(d_u\);若 \(u\) 是叶子,这个系数是 \(p_u\) 到 \(1\) 的路径上的所有点的 \(k\) 的积。

由于 \(d\) 只和树的形态有关,但是每次只修改点权,所以 \(d\) 数组始终不变,最终答案只和 \(a\) 有关。因此修改时我们只需要统计被修改的点权的变化所引起的答案变化即可。

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define per(i, s, e) for(int i = s, i##E = e; i >= i##E; --i)
#define F first
#define S second
#define int ll
#define gmin(x, y) ((x > (y)) && (x = (y)))
#define gmax(x, y) ((x < (y)) && (x = (y)))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double f128;
typedef pair<int, int> pii;
constexpr int N = 1e5 + 5, mod = 998244353;
int n, a[N], k[N], s[N], t[N];
vector<int> to[N];
int qp(int a, int b) {
    int res = 1;
    for(; b; b >>= 1) {
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
    }
    return res;
}
void dfs1(int u, int f) {
    if(to[u].size() == 1) return;
    int K = 0;
    for(auto v : to[u]) if(v != f) {
        dfs1(v, u);
        K = (K + k[v]) % mod;
    }
    int d = to[u].size();
    k[u] = qp((d - K + mod) % mod, mod - 2);
}
void dfs2(int u, int f) {
    if(to[u].size() == 1) s[u] = s[f];
    else s[u] = s[f] * k[u] % mod;
    t[u] = s[u] * to[u].size() % mod;
    for(auto v : to[u]) if(v != f) dfs2(v, u);
}
signed main() {
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
#endif
    cin >> n;
    rep(i, 1, n) cin >> a[i];
    rep(i, 1, n - 1) {
        int u, v; cin >> u >> v;
        to[u].push_back(v);
        to[v].push_back(u);
    }
    dfs1(1, 0);
    s[0] = 1;
    dfs2(1, 0);
    int ans = 0;
    rep(i, 1, n) ans = (ans + a[i] * t[i]) % mod;
    cout << ans << endl;
    int m; cin >> m;
    while(m--) {
        int x, y; cin >> x >> y;
        ans = (ans + t[x] * (y - a[x]) % mod + mod) % mod;
        cout << ans << endl;
        a[x] = y;
    }
    return 0;
}

总结自官方题解:

DP 的本质是在状态 DAG 上跑递推,不能直接转移的原因往往是状态上有环。如果这些环没有公共边,或者说这些状态构成树的形态,可以考虑用设主元的方式,一层层破开转移环,最后计算答案。

标签:得分,int,dfrac,sum,游走,define,cases,节点,mod
From: https://www.cnblogs.com/untitled0/p/random-walk-to-leaves-expected-score-with-modify.html

相关文章

  • 动力节点老杜Vue框架教程【一】Vue程序初体验
    Vue.js是一个渐进式MVVM框架,目前被广泛使用,也成为前端中最火爆的框架Vue可以按照实际需要逐步进阶使用更多特性,也是前端的必备技能动力节点老杜的Vue2+3全家桶教程已经上线咯!学习地址:https://www.bilibili.com/video/BV17h41137i4/视频将从Vue2开始讲解,一步一个案例,知识点......
  • k8s 能做到限制pod在节点的指定cpu核心上运行吗?用--cpuset 方式实现,请给出一个具体案
    在Kubernetes中,可以使用--cpuset方式来限制Pod在节点的指定CPU核心上运行。这可以通过在Pod的yaml文件中设置容器启动命令来实现。具体地,我们可以在容器的启动命令中使用--cpuset选项来指定需要运行的CPU核心。下面是一个典型的使用--cpuset选项的Pod的yaml文件示例:apiVersion:......
  • 设置隐藏节点和不可投票节点
    配置隐藏节点复制集中隐藏节点不能变成主,但是可以参加选举。隐藏节点,最常用的场景是延迟复制。如果不想某个节点变成主节点,将priority设置成0即可如果设置了settings.chainingAllowed,支持辅助节点从另外的复制节点做数据同步,mongodb默认是优先讯在非隐藏节点来做数据同步。如果......
  • Koordinator 一周年,新版本 v1.2.0 支持节点资源预留,兼容社区重调度策略
    作者:佑祎、吕风背景Koordinator是一个开源项目,基于阿里巴巴在容器调度领域多年累积的经验孵化诞生,可以提升容器性能,降低集群资源成本。通过混部、资源画像、调度优化等技术能力,能够提高延迟敏感的工作负载和批处理作业的运行效率和可靠性,优化集群资源使用效率。从2022年4......
  • 19删除链表的倒数第N个节点
    力扣刷题19.删除链表的倒数第N个节点--day4题目分析这道题目比较简单,熟练掌握单链表中删除节点的操作解法ListNode*removeNthFromEnd(ListNode*head,intn){ListNode*dummyHead=newListNode();dummyHead->next=head;ListNode*p=head;int......
  • 24两两交换链表中的节点
    力扣刷题24.两两交换链表中的节点--day4题目分析还是那句话,需要先模拟一下节点交换的过程将整个过程细分为一个个小过程,以此类推下去注意画图分析设置三个指针postcurpre注意1.节点的交换过程2.指针的递推解法ListNode*swapPairs(ListNode*head){if(!......
  • node-red 在功能模块下自定义节点
    在目录下node-red\packages\node_modules\@node-red\nodes\core\function下创建compare.js和compare.html demo.js demo.html确保 data-template-name与RED.nodes.registerType的名称要一致 然后npmrunstart就可以看到 注:https://blog.csdn.net/wmjjjj/artic......
  • 命令行和cmc工具搭建长安链多节点集群和部署智能合约
    这里写目录标题配置环境gitgolanggcc环境搭建源码下载源码编译配置文件生成PermissionedWithCert编译及安装包制作启动节点集群查看节点启动使用正常使用CMC命令行工具部署、调用合约编译&配置部署示例合约长安链部署目录说明参考资料配置环境git下载地址:https://git-scm.com/dow......
  • mysql8主从节点搭建
    设置主从前先创建作为同步数据的用户,可直接在Navicat中创建并对需同步的库授权。注意创建用户的密码插件plugin要保持一致,MySQL8.0设为mysql_native_password,此项可在Navicat直接设置。以192.168.1.1从和192.168.1.2主1、在主节点修改配置文件/etc/my.cnf添加 server......
  • 动力节点⑤章 vuex——vue视频笔记
    5Vuex5.1vuex概述vuex是实现数据集中式状态管理的插件。数据由vuex统一管理。其它组件都去使用vuex中的数据。只要有其中一个组件去修改了这个共享的数据,其它组件会同步更新。一定要注意:全局事件总线和vuex插件的区别:全局事件总线关注点:组件和组件之间数据如何传递,一个绑定$......