题面











2.12 - - -

题解

大概还是挺妙的?

首先基础分和连击分互不干扰,所以可以分开统计。

基础分的统计比较简单,等于:

\[A \sum_{i = l}^{r} p_i
\]

连击分的统计就比较复杂了,因为是求期望,根据期望的线性性,我们可以先算出\(f_i\)表示每个音符的期望连击分,再计算整个区间的期望连击分。

观察连击分的统计方法,可以知道,区间其实是互不干扰的,也就是说,每个区间中的期望连击分,其实都是在对进入这个区间时的期望连击分\(f_{l - 1}\)的一个叠加和增幅。

考虑区间的期望连击分可以表示为:

\[B \sum_{i = l}^r p_i (f_{i - 1} + 1)
\]

因为只有这次打到了完美才可以计入这个音符的贡献,所以这次的贡献是建立在当前音符完美的情况下的,所以贡献就是\(p_i(f_{i - 1} + 1)\)了。

考虑\(f_i\)如何转移。

\[f_i = p_i(f_{i - 1} + 1) + (1 - p_i)f_{i - 1}t
\]

\[= (p_i + t(1 - p_i))f_{i - 1} + p_i
\]

观察到这是一个类似于\(kx + b\)的形式,因此对于一个\(f_i\),如果一个\(j\)满足\(j \le i\),那么一定可以表示为\(f_i = kf_j + b\)的形式。

那么对于区间\([l, r]\),因为其中每个\(f_i\),都可以表示为类似\(kf_{l - 1} + b\)的形式,因此,这个区间的连击分也一定可以表示为\(kf_{l - 1} + b\)的形式。

因此我们考虑线段树,对于区间\([l, r]\)我们维护5个变量,\(k, b, sumb, sumk, sump\),其中\(sump\)是用来算基础分的,\(sumb, sumk\)就是区间连击分的系数,\(k, b\)则是\(f_r = kf_{l - 1} + b\)中的\(k\)和\(b\).

因为\(B\)是对于整个区间的系数,因此我们可以先不考虑它,直接统计后面的部分,最后再乘上\(B\)即可。

因此我们考虑如何合并2个区间\([l, mid], [mid + 1, r]\).

根据前面的推导,现在有

\[f_{mid} = k_l f_{l - 1} + b_l, \quad f_{r} = k_r f_{mid} + b_r
\]

现在要合并这2个变量,我们只需要把后者表示为\(kf_{l - 1} + b\)的形式即可。

所以直接把\(f_{mid}\)带入后面的等式化简就行了,化简出来新变量的\(k = k_l k_r, \quad b = k_rb_l + b_r\)

然后来考虑合并区间信息:

现在我们有:

\[sumk_l f_{l - 1} + sumb_l
\]

\[sumk_r f_{mid} + sumb_r
\]

我们现在要得到的新区间应该要形如第一个区间的样子,因为第一个区间已经是这样了,所以我们只需要转化一下第二个区间,然后和第一个区间加在一起就行了。

我们直接带入上面的\(f_{mid} = k_l f_{l - 1} + b_l\),然后化简并和第一个区间的式子加在一起,最后得到新的\(sumk = sumk_r k_l + sumk_l, \quad sumb = sumk_r b_l + sumb_r + sumb_l\)

最后

\[ans[l][r] = B \cdot sumb[l][r] + A \cdot sump[l][r]
\]

代码

#include<bits/stdc++.h>
using namespace std;
#define R register int
#define LL long long
#define AC 501000
#define ac 2001000
#define p 998244353
#define mo(x) ((x) % p)
#define mul(a, b) (1LL * (a) * (b) % p)//error !!!都要用(a), (b)...啊
#define h(x, y) (mul((x), qpow((y), p - 2))) int n, m, t, A, B;
int pi[AC]; struct node{
int sumk, sumb, k, b, sump;
}tree[ac]; inline int read()
{
int x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
} inline void up(int &a, int b) {a += b; if(a < 0) a += p; if(a >= p) a -= p;}
inline int ad(int a, int b) {a += b; if(a < 0) a += p; if(a >= p) a -= p; return a;} inline int qpow(int x, int have)
{
int rnt = 1;
while(have)
{
if(have & 1) rnt = mul(rnt, x);
x = mul(x, x), have >>= 1;
}
return rnt;
} void pre()
{
n = read();//对于正解来说没有什么用的输入
n = read(), m = read();
int a = read(), b = read();
t = h(a, b), A = read(), B = read();
for(R i = 1; i <= n; i ++) a = read(), b = read(), pi[i] = h(a, b); } node merge(node ll, node rr)
{
node x;
x.k = mul(ll.k, rr.k), x.b = ad(mul(rr.k, ll.b), rr.b);
x.sumk = ad(mul(rr.sumk, ll.k), ll.sumk);
x.sumb = ad(mul(rr.sumk, ll.b), ad(rr.sumb, ll.sumb));
x.sump = ad(ll.sump, rr.sump);
return x;
} #define update(x) tree[x] = merge(tree[x << 1], tree[(x << 1) + 1]); node make(int now)
{
node x;
x.k = ad(pi[now], mul(t, 1 - pi[now]));
x.b = x.sumk = x.sumb = x.sump = pi[now];
return x;
} void build(int x, int ll, int rr)
{
if(ll == rr) {tree[x] = make(ll); return ;}
int mid = (ll + rr) >> 1;
build(x << 1, ll, mid), build((x << 1) + 1, mid + 1, rr);
update(x);
} void change(int x, int l, int r, int w)
{
if(l == r) {tree[x] = make(w); return ;}
int mid = (l + r) >> 1;
if(w <= mid) change(x << 1, l, mid, w);
else change((x << 1) + 1, mid + 1, r, w);
update(x);
} node find(int x, int l, int r, int ll, int rr)
{
if(l == ll && r == rr) return tree[x];
int mid = (l + r) >> 1;
if(rr <= mid) return find(x << 1, l, mid, ll, rr);
else if(ll > mid) return find((x << 1) + 1, mid + 1, r, ll, rr);
else
{
node a = find(x << 1, l, mid, ll, mid);
node b = find((x << 1) + 1, mid + 1, r, mid + 1, rr);
return merge(a, b);
}
} void work()
{
for(R i = 1; i <= m; i ++)
{
int o = read();
if(!o)
{
int x = read(), a = read(), b = read();
pi[x] = h(a, b), change(1, 1, n, x);
}
else
{
int ll = read(), rr = read();
node x = find(1, 1, n, ll, rr);
//int ans = mul(ad(mul(x.sumk, pi[ll]), ad(x.sumb, pi[ll])), B);
int ans = mul(x.sumb, B);
up(ans, mul(A, x.sump));
printf("%d\n", ans);
}
}
} int main()
{
freopen("in.in", "r", stdin);
pre();
build(1, 1, n);
work();
fclose(stdin);
return 0;
}

Omeed 线段树的更多相关文章

  1. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  2. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  3. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  4. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  5. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

  6. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

  7. CF719E(线段树+矩阵快速幂)

    题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作 分析:线段树 线段树的每个节点表示(f[i],f[i-1])这 ...

  8. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

  9. 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

随机推荐

  1. 10_SpringBoot集成TkMybatis插件

    10_SpringBoot集成TkMybatis插件 明天你好向前奔跑 关注  0.5 2018.09.11 11:15 字数 163 阅读 3794评论 0喜欢 3 @Author Jacky Wa ...

  2. 一个非常好用的PHP数组函数

    array_column 该函数非常有用,在PHP 5.5中可直接调用. 有如下二维数组,如要抽取每个子数组中的特定项. <?php // Array representing a possib ...

  3. Sublime Text3.0的安装

    Sublime Text是一款轻量级的易于使用的前端编写软件,个人比较推荐. 找到Sublime的官网,下载对应的版本后,点击安装.安装完成后需要下载相应的插件才能进行更加 有效率的开发工作.编写前端 ...

  4. 列出连通集(mooc)

    给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集.假设顶点从0到N−1编号.进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点. 输入格式: 输入第1 ...

  5. Vue-lazyload 的使用

    Vue 项目使用 Vue-lazyload 做图片懒加载. 下载 下载 Vue-lazyload 的包NPM包 npm install vue-lazyload --save 引入 在项目 main. ...

  6. 使用calendar日历插件实现动态展示会议信息

    效果图如下,标红色为有会议安排,并跳转详细会议信息页面. html页面 <%@ page contentType="text/html;charset=UTF-8"%> ...

  7. golang笔记2_程序结构

    golang程序结构 2.1 命名 Golang中的命名遵循这样一个简单原则,名字的开头必须是字母或者下划线,后面跟字母.数字或者下划线(这里与C语言中是一致的). 在函数内部声明的实体,即局部变量, ...

  8. scrapy+selenium+chromedriver解析动态渲染页面

    背景:动态页面是页面是通过js代码渲染出来的,无法直接使用scrapy爬虫,这是就需要先把js代码转为静态的html,再用scrapy爬虫就可以解决 解决办法:增加SeleniumMiddleware ...

  9. CentOS-6.x系列查看cpu核数

    使用CentOS7.x使用习惯了后用top命令,然后按1就可以查看相关的cpu核心数等相关信息 相关概念: 物理CPU:实际Server中插槽上的CPU个数. 物理cpu数量:可以数不重复的 phys ...

  10. centos上搭建git服务--4

    Git是目前世界上最先进的分布式版本控制系统(没有之一).使用Svn的请参考<版本控制-svn服务器搭建和常用命令(centos 6.3)>,下面介绍Git的常用命令 常用命令 简单版 升 ...