• 【bzoj4499】线性函数 线段树


    题目描述

    小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 (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


    题解

    线段树

    由于所有函数都是一次函数,因此它们复合形成的函数也一定是一次函数。

    于是我们可以使用线段树来维护每个区间从右到左复合所得的一次函数的$k$和$b$。

    具体方法:设左边是$y=k'x+b'$,右边是$y=k''x+b''$,那么复合得到的函数为$y=k''(k'x+b')+b''=k'k''x+k''b'+b''$,所以新的$k$为$k'k''$,$b$为$k''b'+b''$。

    时间复杂度$O(mlog n)$。

    #include <cstdio>
    #define N 200010
    #define mod 1000000007
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    typedef long long ll;
    struct data
    {
    	ll k , b;
    	data operator+(const data &a)const
    	{
    		data ans;
    		ans.k = k * a.k % mod , ans.b = (a.k * b + a.b) % mod;
    		return ans;
    	}
    }a[N << 2] , t;
    char str[10];
    inline void pushup(int x)
    {
    	a[x] = a[x << 1] + a[x << 1 | 1];
    }
    void build(int l , int r , int x)
    {
    	if(l == r)
    	{
    		scanf("%lld%lld" , &a[x].k , &a[x].b);
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(lson) , build(rson);
    	pushup(x);
    }
    void update(int p , int l , int r , int x)
    {
    	if(l == r)
    	{
    		scanf("%lld%lld" , &a[x].k , &a[x].b);
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(p <= mid) update(p , lson);
    	else update(p , rson);
    	pushup(x);
    }
    data query(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e) return a[x];
    	int mid = (l + r) >> 1;
    	if(e <= mid) return query(b , e , lson);
    	else if(b > mid) return query(b , e , rson);
    	else return query(b , e , lson) + query(b , e , rson);
    }
    int main()
    {
    	int n , m , x , y;
    	ll z;
    	scanf("%d%d" , &n , &m);
    	build(1 , n , 1);
    	while(m -- )
    	{
    		scanf("%s%d" , str , &x);
    		if(str[0] == 'M') update(x , 1 , n , 1);
    		else scanf("%d%lld" , &y , &z) , t = query(x , y , 1 , n , 1) , printf("%lld
    " , (t.k * z + t.b) % mod);
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    Sublime Text3 无法调出package controll问题
    Python标准库-enumerate用法
    设计模式学习-简单工厂模式(python3)
    【IO流】java中文件路径(相对路径、绝对路径)相关类及方法
    nginx安装教程(详细)
    nginx -stream(tcp连接)反向代理配置 实现代理mysql以及文件上传
    【单例模式】懒汉式的线程安全问题 volatile的作用
    jsonp协议 java服务端、JQuery客户端 简单实现原理
    MyBatis原理,Spring、SpringBoot整合MyBatis
    【JavaSE】运行时类型信息(RTTI、反射)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7657056.html
Copyright © 2020-2023  润新知