您的位置:首页 > 其它

线性函数

2016-03-24 16:16 381 查看

                                                 时间限制:2s   内存限制:256mb

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

输入格式:
第一行两个整数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
数据范围:

20% : n, m <= 1000
另外10% :b = 0
另外10% :k = 1
100%:1 <= n, m <= 200,000,0 <= k, b, x < 1000,000,007

题解:  

  考虑到三个线性函数 k1 * x + b1,k2 * x + b2,k3 * x + b3。  

  先复合前两个函数,后复合第三个函数的结果是:k3*(k2*(k1*x+b1)+b2)+b3=k1*k2*k3*x+b1*k2*k3+b2*k3+b3。

    先复合后两个函数:k3(k2*x+b2)+b3=k2*k3*x+b2*k3+b3,再复合第一个函数:k1*k2*k3*x+b1*k2*k3+b2*k3+b3。
  两个结果是一样的,所以函数的复合满足结合律。
  或者用矩阵来证明,线性函数可以用一个矩阵来表示,而矩阵乘法是具有结合律的,所以线性函数的复合也满足结合律。
     有了上述性质,就可以利用线段树维护区间的复合函数,这样就可以在时间内算出答案。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const LL mod=1e9+7,maxn=200010;
LL N,M,k[maxn],b[maxn];
char s[10];
struct Tree{
LL l,r,k,b;
Tree(){ k=1; b=0; }
}T[maxn*10];
inline Tree unionn(Tree x,Tree y){
Tree ans;
ans.k=(x.k*y.k)%mod; ans.b=((x.b*y.k)%mod+y.b)%mod;
return ans;
}
inline void update(LL rt){
T[rt].k=(T[rt<<1].k*T[rt<<1|1].k)%mod;
T[rt].b=((T[rt<<1].b*T[rt<<1|1].k)%mod+T[rt<<1|1].b)%mod;
}
inline void build(LL rt,LL l,LL r){
T[rt].l=l; T[rt].r=r;
if(l==r){
T[rt].k=k[l]%mod; T[rt].b=b[l]%mod;
return ;
}
LL mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
update(rt);
}
inline void change(LL rt,LL pos,LL K,LL B){
if(T[rt].l==T[rt].r){
T[rt].k=K; T[rt].b=B;
return ;
}
LL mid=(T[rt].l+T[rt].r)>>1;
if(pos<=mid) change(rt<<1,pos,K,B);
else change(rt<<1|1,pos,K,B);
update(rt);
}
inline Tree query(LL rt,LL l,LL r){
if(l<=T[rt].l&&T[rt].r<=r){
return T[rt];
}
LL mid=(T[rt].l+T[rt].r)>>1;
Tree ans;
if(l<=mid) ans=unionn(ans,query(rt<<1,l,r));
if(mid+1<=r) ans=unionn(ans,query(rt<<1|1,l,r));
return ans;
}
int main(){
//    freopen("func.in","r",stdin);
//    freopen("func.out","w",stdout);
scanf("%lld%lld",&N,&M);
for(int i=1;i<=N;i++) scanf("%lld%lld",&k[i],&b[i]);
build(1,1,N);
while(M--){
LL x,y,z;
scanf("%s%lld%lld%lld",s,&x,&y,&z);
if(s[0]=='Q'){
Tree tmp=query(1,x,y);
LL ans=((tmp.k*z)%mod+tmp.b)%mod;
printf("%lld\n",ans);
}
else change(1,x,y,z);
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: