bzoj4499线性函数 线段树区间合并

Posted GXZlegend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4499线性函数 线段树区间合并相关的知识,希望对你有一定的参考价值。

题目描述

小C最近在学习线性函数,线性函数可以表示为:f(x) = kx + b。现在小C面前有n个线性函数fi(x)=kix+bi ,他对这n个线性函数执行m次操作,每次可以:
1.M i K B 代表把第i个线性函数改为:fi(x)=kx+b 。
2.Q l r x 返回fr(fr-1(...fl(x)))  mod  10^9+7 。

输入

第一行两个整数n, m (1 <= n, m <= 200,000)。
接下来n行,每行两个整数ki, bi。
接下来m行,每行的格式为M i K B或者Q l r x。

输出

对于每个Q操作,输出一行答案。

样例输入

5 5
4 2
3 6
5 7
2 6
7 5
Q 1 5 1
Q 3 3 2
M 3 10 6
Q 1 4 3
Q 3 4 4

样例输出

1825
17
978
98


题解

线段树区间合并

由于所有函数都是一次函数,因此它们复合形成的函数也一定是一次函数。

于是我们可以使用线段树区间合并的方法来维护每个区间从右到左复合所得的一次函数的$k$和$b$。具体方法:设左边是$y=k‘x+b‘$,右边是$y=k‘‘x+b‘‘$,那么复合得到的函数为$y=k‘‘(k‘x+b‘)+b‘‘=k‘k‘‘x+k‘‘b‘+b‘‘$,所以新的$k$为$k‘k‘‘$,$b$为$k‘‘b‘+b‘‘$。

按照区间合并的方法维护即可。

时间复杂度$O(m\log n)$。

#include <cstdio>
#define N 200010
#define mod 1000000007
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
typedef long long ll;
struct data
{
	ll k , b;
	data operator+(const data &a)const
	{
		data ans;
		ans.k = k * a.k % mod , ans.b = (a.k * b + a.b) % mod;
		return ans;
	}
}a[N << 2] , t;
char str[10];
inline void pushup(int x)
{
	a[x] = a[x << 1] + a[x << 1 | 1];
}
void build(int l , int r , int x)
{
	if(l == r)
	{
		scanf("%lld%lld" , &a[x].k , &a[x].b);
		return;
	}
	int mid = (l + r) >> 1;
	build(lson) , build(rson);
	pushup(x);
}
void update(int p , int l , int r , int x)
{
	if(l == r)
	{
		scanf("%lld%lld" , &a[x].k , &a[x].b);
		return;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) update(p , lson);
	else update(p , rson);
	pushup(x);
}
data query(int b , int e , int l , int r , int x)
{
	if(b <= l && r <= e) return a[x];
	int mid = (l + r) >> 1;
	if(e <= mid) return query(b , e , lson);
	else if(b > mid) return query(b , e , rson);
	else return query(b , e , lson) + query(b , e , rson);
}
int main()
{
	int n , m , x , y;
	ll z;
	scanf("%d%d" , &n , &m);
	build(1 , n , 1);
	while(m -- )
	{
		scanf("%s%d" , str , &x);
		if(str[0] == ‘M‘) update(x , 1 , n , 1);
		else scanf("%d%lld" , &y , &z) , t = query(x , y , 1 , n , 1) , printf("%lld\n" , (t.k * z + t.b) % mod);
	}
	return 0;
}

 

 

以上是关于bzoj4499线性函数 线段树区间合并的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 4568: [Scoi2016]幸运数字树链剖分+线段树+线性基

BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

「bzoj 4184: shallot」

bzoj 2243: [SDOI2011]染色 (树链剖分+线段树 区间合并)

神奇的操作——线段树合并(例题: BZOJ2212)