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
*/