题目传送门
牛可乐有 n n n 个一次函数,第 i i i 个函数为 f i ( x ) = k i × x + b i f_i(x)=k_i\times x+b_i fi(x)=ki×x+bi。
牛可乐有 m m m 次操作,每次操作为以下二者其一:
• 1 i k b \text{1 i k b} 1 i k b 将 f i ( x ) f_i(x) fi(x) 修改为 f i ( x ) = k × x + b f_i(x)=k\times x+b fi(x)=k×x+b
• 2 l r \text{2 l r} 2 l r 求 f r ( f r − 1 ( ⋯ ( f l + 1 ( f l ( 1 ) ) ) ⋯ ) ) f_r\left(f_{r-1}\left(\cdots\left(f_{l+1}\left(f_l(1)\right)\right)\cdots\right)\right) fr(fr−1(⋯(fl+1(fl(1)))⋯))。
牛可乐当然(bu)会做啦,他想考考你——
答案对 1 0 9 + 7 10^9+7 109+7 取模。
第一行,两个正整数 n , m n,m n,m 。
第二行,n 个整数 k 1 , k 2 , … , k n k_1,k_2,\dots,k_n k1,k2,…,kn 。
第三行,n 个整数 b 1 , b 2 , … , b n b_1,b_2,\dots,b_n b1,b2,…,bn 。
接下来 m 行,每行一个操作,格式见上。
保证 1 ≤ n , m ≤ 2 × 1 0 5 1\leq n,m\leq 2\times 10^5 1≤n,m≤2×105 , 0 ≤ k i , b i < 1 0 9 + 7 ,0\leq k_i,b_i < 10^9+7 ,0≤ki,bi<109+7。
对于每个求值操作,输出一行一个整数,表示答案。
2 3
1 1
1 0
1 2 114514 1919810
2 1 2
2 1 1
2148838
2
初始 f 1 ( x ) = x + 1 , f 2 ( x ) = x f_1(x)=x+1,f_2(x)=x f1(x)=x+1,f2(x)=x
修改后 f 2 ( x ) = 114514 x + 1919810 f_2(x)=114514x+1919810 f2(x)=114514x+1919810
查询时 f 1 ( 1 ) = 2 , f 2 ( f 1 ( 1 ) ) = 2148838 f_1(1)=2,f_2(f_1(1))=2148838 f1(1)=2,f2(f1(1))=2148838
f r ( f r − 1 ( . . . ( f l + 1 ( f l ( 1 ) ) ) . . . ) ) = ∏ i = l r k i + ∑ i = l r b i ∏ j = i + 1 r k j f_r(f_{r-1}(...(f_{l+1}(f_l(1)))...)) \\ =\prod_{i=l}^rk_i\ +\ \sum_{i=l}^rbi\prod_{j=i+1}^rk_j fr(fr−1(...(fl+1(fl(1)))...))=∏i=lrki + ∑i=lrbi∏j=i+1rkj
注 意 : i + 1 > r i + 1 > r 时 视 ∏ j = i + 1 r k j = 1 注意: i+1>ri+1>r 时视 \prod_{j=i+1}^r{k_j}=1 注意:i+1>ri+1>r时视∏j=i+1rkj=1 。
对加号左右分别用线段树维护,考虑如何合并两个相邻区间 [ l 1 , r 1 ] , [ r 1 + 1 , r 2 ] [l_1,r_1], [r1+1,r_2] [l1,r1],[r1+1,r2]
∏ i = l 1 r 1 k i = n 1 , ∏ i = l 2 r 2 k i = n 2 ∑ i = l 1 r 1 b i ∏ j = i + 1 r k j = m 1 , ∑ i = l 2 r 2 b i ∏ j = i + 1 r k j = m 2 \prod_{i=l_1}^{r_1}k_i=n_1, \prod_{i=l_2}^{r_2}k_i=n_2 \\ \sum_{i=l_1}^{r_1}{b_i\prod_{j=i+1}^r{k_j}}=m_1,\sum_{i=l_2}^{r_2}{b_i\prod_{j=i+1}^r{k_j}}=m_2 ∏i=l1r1ki=n1,∏i=l2r2ki=n2∑i=l1r1bi∏j=i+1rkj=m1,∑i=l2r2bi∏j=i+1rkj=m2
区间 [ l 1 , r 2 ] [l_1,r_2] [l1,r2] 的 ∏ k i = n 1 × n 2 \prod k_i=n_1\times n_2 ∏ki=n1×n2, ∑ b i ∏ k j = m 1 × n 2 + m 2 \sum{b_i\prod k_j}=m_1\times n_2+m_2 ∑bi∏kj=m1×n2+m2
一棵线段树维护 ∏ k i \prod k_i ∏ki ,另一棵维护 ∑ b i ∏ k j \sum{b_i\prod k_j} ∑bi∏kj 即可。
视 n , m n,m n,m 同阶,时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
#include
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
int k[maxn];
int b[maxn];
struct Mat {
ll m[2][2];
int left, right;
Mat() { memset(m, 0, sizeof m); } // 注意初始化m数组,处理下随机值
friend Mat operator * (const Mat& a, const Mat& b) {
Mat res;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j) {
for (int k = 0; k < 2; ++k)
res.m[i][j] += (a.m[i][k] * b.m[k][j]) % mod;
res.m[i][j] %= mod;
}
return res;
}
};
struct SegTree {
#define mid ((l+r)>>1)
Mat tree[maxn << 2];
void PushUp(int rt) {
int l = tree[rt].left; // 由于Mat里存储了l、r,乘法操作的时候返回新的Mat,导致l,r丢失,预先存起来,避免l、r不见了
int r = tree[rt].right;
tree[rt] = tree[rt << 1] * tree[rt << 1 | 1];
tree[rt].left = l;
tree[rt].right = r;
}
void build(int rt, int l, int r) {
tree[rt].left = l;
tree[rt].right = r;
if (l == r) {
tree[rt].m[0][0] = k[l];
tree[rt].m[1][0] = b[r];
tree[rt].m[1][1] = 1;
return;
}
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
PushUp(rt);
}
void update(int rt, int pos) {
if (tree[rt].left == tree[rt].right) {
tree[rt].m[0][0] = k[tree[rt].left];
tree[rt].m[1][0] = b[tree[rt].right];
return;
}
int md = (tree[rt].left + tree[rt].right) >> 1;
if (pos <= md) update(rt << 1, pos);
else update(rt << 1 | 1, pos);
PushUp(rt);
}
Mat query(int rt, int l, int r) {
if (l <= tree[rt].left && tree[rt].right <= r) return tree[rt];
Mat res; res.m[0][0] = res.m[1][1] = 1; // 初始化为单位阵
int md = (tree[rt].left + tree[rt].right) >> 1;
if (l <= md) res = res * query(rt << 1, l, r);
if (r > md) res = res * query(rt << 1 | 1, l, r);
return res;
}
#undef mid
};
SegTree st;
int main() {
ios;
int n, m; while (cin >> n >> m) {
for (int i = 1; i <= n; ++i) cin >> k[i];
for (int i = 1; i <= n; ++i) cin >> b[i];
st.build(1, 1, n);
while (m--) {
int x, i, k, b, l, r; cin >> x;
Mat ans; ans.m[0][0] = ans.m[0][1] = 1;
if (x & 1) {
cin >> i >> k >> b;
::k[i] = k % mod, ::b[i] = b % mod;
st.update(1, i);
}
else {
cin >> l >> r;
ans = ans * st.query(1, l, r);
cout << ans.m[0][0] << endl;
}
}
}
return 0;
}