线性函数
时间限制: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; }
- 垃圾收集算法
- F - Count the Colors
- ubuntu下使用OBS开斗鱼直播
- cssHack
- 学习、阅读笔记——jsonP&Ajax
- java中的强、软、弱和虚引用
- String与InputStream的互相转换
- SecureCRT远程登录ubuntu
- Python datetime的简单使用
- 204. Count Primes
- 高性能网关设备及服务实践
- PHP操作SQLITE
- SVN的使用
- MongoDB 2.6.x 的安装部署
- C++中求类的大小
- ElasticSearch 2 (33) - 信息聚合系列之聚合过滤
- css3中的边框相关样式
- hive json数据生成和处理
- SQL的四种连接-左外连接、右外连接、内连接、全连接
- 每天一个linux命令(60):scp命令 【转】