BZOJ 4466 线性函数

题目描述

小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
接下来n行,每行两个整数ki, bi。
接下来m行,每行的格式为M i K B或者Q l r x。
1 <= n, m <= 200,000,0 <= k, b, x < 1000,000,007

输出格式

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

Sample Input

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

Sample Output

1825
17
978
98

考试T1,
考试时,我信心满满的打完就睡觉。结果这个最应该满分的只有20pts。。。

我的做法是,线段树上维护 b_i * k_{i+1] * k_{i+2] * ... * k_n , 然后统一除以 k_{r+1] * k_{r+2] * .. * k_n
得到除了x之外的那部分。

然而他有0

然而他有0

然而他有0

然后我就挂了

扯淡结束

正解,
可以对每个区间维护出它的复合函数。也就是把这一段的函数综合到一起。
设左区间的 为 y = k1 * x + b1 , 右区间的是 y = k2 * x + b2
那么新的就是 y = k1 * k2 * x + b1 * k2 + b2
K = k1 * k2 , B = b1 * k2 + b2;
然后它就没了 , 我就自闭了。。。

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<bitset>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 5e5+10 , mod = 1e9+7;
inline int read()
{
    register int x = 0 , f = 0; register char c = getchar();
    while(c < '0' || c > '9') f |= c == '-' , c = getchar();
    while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
    return f ? -x : x;
}
#define int long long
int n , m;
int B[N] , K[N];

int ksm(int a , int k) { int ans = 1; a %= mod; for( ; k ; k >>= 1 , a = (LL)a * a % mod) if(k & 1) ans = (LL)ans * a % mod; return ans; }

namespace Work1
{
	int calc(int x , int id) { return ((LL)x * K[id] % mod + B[id]) % mod; }
	
	void solve()
	{
		char c[5];
		while(m--)
		{
			scanf("%s" , c);
			if(c[0] == 'M')
			{
				int pos = read() , k = read() , b = read();
				K[pos] = k; B[pos] = b;
			}
			else
			{
				int l = read() , r = read() , x = read();
				for(int i = l ; i <= r ; ++i) x = calc(x , i);
				cout << x << '\n';
			}
		}
		return ;
	}
}

namespace Work2
{
	struct node
	{ 
		LL b , k; 
		friend node operator + (const node &A , const node &B)
		{
			node C;
			C.k = A.k * B.k % mod; C.b = (A.b * B.k % mod + B.b) % mod;
			return C;
		}
	}tr[N<<2];
	#define lson k << 1 , l , mid
	#define rson k << 1 | 1 , mid + 1 , r
	
	inline void update(int k) { tr[k] = tr[k<<1] + tr[k<<1|1]; return ; }

	void build(int k , int l , int r)
	{
		if(l == r) { tr[k].b = B[l]; tr[k].k = K[l]; return ; }
		int mid = (l + r) >> 1;
		build(lson); build(rson); return update(k);
	}

	void modify(int k , int l , int r , int pos)
	{
		if(l == r) { tr[k].b = B[l]; tr[k].k = K[l]; return ; }
		int mid = (l + r) >> 1;
		if(pos <= mid) modify(lson , pos); else modify(rson , pos); return update(k);
	}
	
	node Ask(int k , int l , int r , int x , int y)
	{
		if(x <= l && r <= y) return tr[k];
		int mid = (l + r) >> 1;
		if(x >  mid) return Ask(rson , x , y);
		if(y <= mid) return Ask(lson , x , y);
		return Ask(lson , x , y) + Ask(rson , x , y);
	}

	void solve()
	{
		build(1 , 1 , n); char c[5];
		while(m--)
		{
			scanf("%s" , c);
			if(c[0] == 'M')
			{
				int pos = read(); K[pos] = read(); B[pos] = read();
				modify(1 , 1 , n , pos);
			}
			else
			{
				int l = read() , r = read() , x = read();
				node tmp = Ask(1 , 1 , n , l , r);
				cout << (x * tmp.k % mod + tmp.b) % mod << '\n';
			}
		}
		return ;
	}
}

signed main()
{
	freopen("olinr.in" , "r" , stdin); freopen("olinr.out" , "w" , stdout);
	n = read(); m = read();
	for(int i = 1 ; i <= n ; ++i) K[i] = read() , B[i] = read();
	if(n <= 3000 && m <= 3000) Work1::solve(); else Work2::solve();
	fclose(stdin); fclose(stdout);
	return 0;
}
/*
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
*/
posted @ 2020-04-14 15:03  沙野博士  阅读(245)  评论(2编辑  收藏  举报