• 线性函数


                                                     时间限制: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。
      两个结果是一样的,所以函数的复合满足结合律。
      或者用矩阵来证明,线性函数可以用一个矩阵来表示,而矩阵乘法是具有结合律的,所以线性函数的复合也满足结合律。
         有了上述性质,就可以利用线段树维护区间的复合函数,这样就可以在时间内算出答案。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<queue>
     8 #include<vector>
     9 using namespace std;
    10 typedef long long LL;
    11 const LL mod=1e9+7,maxn=200010;
    12 LL N,M,k[maxn],b[maxn];
    13 char s[10];
    14 struct Tree{
    15     LL l,r,k,b;
    16     Tree(){ k=1; b=0; }
    17 }T[maxn*10];
    18 inline Tree unionn(Tree x,Tree y){
    19     Tree ans;
    20     ans.k=(x.k*y.k)%mod; ans.b=((x.b*y.k)%mod+y.b)%mod;
    21     return ans;
    22 }
    23 inline void update(LL rt){
    24     T[rt].k=(T[rt<<1].k*T[rt<<1|1].k)%mod;
    25     T[rt].b=((T[rt<<1].b*T[rt<<1|1].k)%mod+T[rt<<1|1].b)%mod;
    26 }
    27 inline void build(LL rt,LL l,LL r){
    28     T[rt].l=l; T[rt].r=r;
    29     if(l==r){
    30         T[rt].k=k[l]%mod; T[rt].b=b[l]%mod;
    31         return ;
    32     }
    33     LL mid=(l+r)>>1;
    34     build(rt<<1,l,mid);
    35     build(rt<<1|1,mid+1,r);
    36     update(rt);
    37 }
    38 inline void change(LL rt,LL pos,LL K,LL B){
    39     if(T[rt].l==T[rt].r){
    40         T[rt].k=K; T[rt].b=B;
    41         return ;
    42     }
    43     LL mid=(T[rt].l+T[rt].r)>>1;
    44     if(pos<=mid) change(rt<<1,pos,K,B);
    45     else change(rt<<1|1,pos,K,B);
    46     update(rt);
    47 }
    48 inline Tree query(LL rt,LL l,LL r){
    49     if(l<=T[rt].l&&T[rt].r<=r){
    50         return T[rt];
    51     }
    52     LL mid=(T[rt].l+T[rt].r)>>1;
    53     Tree ans;
    54     if(l<=mid) ans=unionn(ans,query(rt<<1,l,r));
    55     if(mid+1<=r) ans=unionn(ans,query(rt<<1|1,l,r));
    56     return ans;
    57 }
    58 int main(){
    59 //    freopen("func.in","r",stdin);
    60 //    freopen("func.out","w",stdout);
    61     scanf("%lld%lld",&N,&M);
    62     for(int i=1;i<=N;i++) scanf("%lld%lld",&k[i],&b[i]);
    63     build(1,1,N);
    64     while(M--){
    65         LL x,y,z;
    66         scanf("%s%lld%lld%lld",s,&x,&y,&z);
    67         if(s[0]=='Q'){
    68             Tree tmp=query(1,x,y);
    69             LL ans=((tmp.k*z)%mod+tmp.b)%mod;
    70             printf("%lld
    ",ans);
    71         }
    72         else change(1,x,y,z);
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    变量定义方法
    动态编译
    函数
    过程
    触发器
    高级聚合函数rollup(),cube(),grouping sets()
    高级函数-decode
    高级函数-sign
    js 保留两位小数 javascript
    js 发红包
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/5315999.html
Copyright © 2020-2023  润新知