2020牛客寒假算法基础集训营2 - J 求函数 (线段树)
链接:https://ac.nowcoder.com/acm/contest/3003/J
来源:牛客网
求函数
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
输入描述:
第一行,两个正整数 n,m 。
第二行,n 个整数 k1,k2,…,knk_1,k_2,\dots,k_nk1,k2,…,kn 。
第三行,n 个整数 b1,b2,…,bnb_1,b_2,\dots,b_nb1,b2,…,bn。
接下来 m 行,每行一个操作,格式见上。
保证 1≤n,m≤2×1051\leq n,m\leq 2\times 10^51≤n,m≤2×105,0≤ki,bi<109+70\leq k_i,b_i < 10^9+70≤ki,bi<109+7。
输出描述:
对于每个求值操作,输出一行一个整数,表示答案。
示例1
输入
复制
2 3
1 1
1 0
1 2 114514 1919810
2 1 2
2 1 1
输出
复制
2148838
2
说明
初始 f1(x)=x+1,f2(x)=xf_1(x)=x+1,f_2(x)=xf1(x)=x+1,f2(x)=x
修改后 f2(x)=114514x+1919810f_2(x)=114514x+1919810f2(x)=114514x+1919810
查询时 f1(1)=2,f2(f1(1))=2148838f_1(1)=2,f_2(f_1(1))=2148838f1(1)=2,f2(f1(1))=2148838
思路:
我们观察以下数据:
\(f_1(1)=k1+b1=(k1)+(b1)\)
\(f_2(f_1(1))=k2*(f_1(1))+b2=k2*k1+k2*b1+b2=(k2*k1)+(k2*b1+b2)\)
\(f_3(f_2(f_1(1)))=(k3*k2*k1)+(k3*k2*b1+k3*b2+b3)\)
我们不妨设括号的左边部分为first,右边部分为second
容易观察出 \(f_3(f_2(f_1(1)))=[k3*(f_2(f_1(1)).first)]+[k3*(f_2(f_1(1)).second)+b3]\)
右式中前中括号部分为\(f_3(...).first\) ,后面的中括号部分为\(f_3(...).second\)
于是我们不难发现将上式中的数字3换成r,数字1换成l,数字2换成mid 也同样满足
即:\(f_r(f_{r-1}(⋯f_l(1)⋯)).first=(f_{[mid+1,r]}(1).first)*(f_{[l,mid]}(1).first)\)
\(f_r(f_{r-1}(⋯f_l(1)⋯)).second=(f_{[mid+1,r]}(1).first)*((f_{[l,mid]}(1).second))+(f_{[mid+1,r]}(1).second)\)
这样我们就可以用线段树来分别维护一个区间\([l,r]\)的first 部分和second 部分
first部分其实为\(\prod_{i=l}^r k_i\)
second部分其实为\(\sum_{i=l}^r (b_i*\prod_{j=i+1}^r k_j)\)
区间的合并公式上面已经给了,记得全程取模即可。
代码:
#include
#include
#include
#include
#include
#include
#include
#include