线性函数 题解

线性函数 题解

题目描述

小 C 最近在学习线性函数,线性函数可以表示为: f ( x ) = k ∗ x + b f(x)=k*x+b f(x)=kx+b
现在小 C 面前有 n n n 个线性函数 f i ( x ) = k i ∗ x + b i f_i(x)=k_i*x+b_i fi(x)=kix+bi,他对这 n n n 个线性函数执行 m m m 次操作,每次可以:
1 M i k b 代表把第 i i i 个线性函数改为 f i ( x ) = k ∗ x + b f_i(x)=k*x+b fi(x)=kx+b
2 Q l r x 返回 f r ( f r − 1 ( ⋯ ( f l ( x ) ) ) m o d    1 0 9 + 7 f_r(f_{r-1}(\cdots(f_l(x))) \mod 10^9+7 fr(fr1((fl(x)))mod109+7

题解

考虑到三个线性函数 k 1 ∗ x + b 1 k_1 * x + b_1 k1x+b1 k 2 ∗ x + b 2 k_2 * x + b_2 k2x+b2 k 3 ∗ x + b 3 k_3 * x + b_3 k3x+b3
如果先复合前两个函数,后复合第三个函数的结果是: k 3 ∗ ( k 2 ∗ ( k 1 ∗ x + b 1 ) + b 2 ) + b 3 = k 1 ∗ k 2 ∗ k 3 ∗ x + b 1 ∗ k 2 ∗ k 3 + b 2 ∗ k 3 + b 3 k_3*(k_2*(k_1*x+b_1)+b_2)+b_3=k_1*k_2*k_3*x+b_1*k_2*k_3+b_2*k_3+b_3 k3(k2(k1x+b1)+b2)+b3=k1k2k3x+b1k2k3+b2k3+b3

如果先复合后两个函数,,再复合第一个函数的结果是: k 3 ( k 2 ∗ x + b 2 ) + b 3 = k 2 ∗ k 3 ∗ x + b 2 ∗ k 3 + b 3 = k 1 ∗ k 2 ∗ k 3 ∗ x + b 1 ∗ k 2 ∗ k 3 + b 2 ∗ k 3 + b 3 k_3(k_2*x+b_2)+b_3=k_2*k_3*x+b_2*k_3+b_3=k_1*k_2*k_3*x+b_1*k_2*k_3+b_2*k_3+b_3 k3(k2x+b2)+b3=k2k3x+b2k3+b3=k1k2k3x+b1k2k3+b2k3+b3

可以发现两个结果是一样的,所以函数的复合满足结合律。那么,就可以利用线段树维护区间的复合函数,这样就可以求出答案了。

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
# define int long long
# define rd(t) read <t> ()
# define mem(a, b) memset (a, b, sizeof (a))
# define fi first
# define se second
# define lc u << 1
# define rc u << 1 | 1
# define debug printf ("debug\n")
const int N = 200005, mod = 1e9 + 7; 
template <typename tr> inline tr read ()
{
    tr s = 0; int w = 1; char c = getchar (); 
    for (; !isdigit (c); c = getchar ()) { if (c == '-') w = -1; }
    for (; isdigit (c); c = getchar ()) s = (s << 1) + (s << 3) + c - '0';
    return s * w;
}

int n, m; 
int k[N], b[N]; 
char s[10]; 
struct tree
{
	int l, r, k, b; 
	tree () { k = 1, b = 0; } 
	tree operator + (const tree &t) const
	{
		tree ans; 
		ans.k = (k * t.k) % mod; ans.b = ((b * t.k) % mod + t.b) % mod; 
		return ans; 
	}
} tr[N << 2];
void pushup (int u) 
{
    tr[u].k = (tr[lc].k * tr[rc].k) % mod;
    tr[u].b = ((tr[lc].b * tr[rc].k) % mod + tr[rc].b) % mod;
}
void build (int u, int l, int r)
{
	tr[u].l = l, tr[u].r = r; 
	if (l == r)
	{
		tr[u].k = k[l] % mod, tr[u].b = b[l] % mod; 
		return; 
	}
	int mid = l + r >> 1; 
	build (lc, l, mid), build (rc, mid + 1, r); 
	pushup (u); 
} 
void modify (int u, int x, int k, int b)
{
	int l = tr[u].l, r = tr[u].r; 
	if (l == r)
	{
		tr[u].k = k, tr[u].b = b; 
		return; 
	}
	int mid = l + r >> 1; 
	if (x <= mid) modify (lc, x, k, b); 
	else modify (rc, x, k, b); 
	pushup (u); 
}
tree query (int u, int x, int y)
{
	int l = tr[u].l, r = tr[u].r; 
	if (x <= l && y >= r) return tr[u]; 
	int mid = l + r >> 1; 
	tree ans; 
	if (x <= mid) ans = ans + query (lc, x, y); 
	if (y > mid) ans = ans + query (rc, x, y); 
	return ans; 
}
signed main ()
{
	n = rd (int), m = rd (int); 
	for (int i = 1; i <= n; i ++ ) k[i] = rd (int), b[i] = rd (int); 
	build (1, 1, n); 
	while (m -- )
	{
		string s; int x, y, z; cin >> s >> x >> y >> z; 
		if (s == "M") modify (1, x, y, z); 
		else
		{
			tree ans = query (1, x, y); 
			int res = (ans.k * z % mod + ans.b) % mod; 
			printf ("%lld\n\n", res); 
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值