• 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 << '
    ';
    			}
    		}
    		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 << '
    ';
    			}
    		}
    		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
    */
    
  • 相关阅读:
    通过一个程序来理解PHP里面的抽象类【1】
    mycheckpoint 把玩手记
    Mysql 大量 unauthenticated user
    零基础学习Oracle 10G视频教程
    mysql show processlist命令 详解
    c# 中的事件
    c# 中方法签名 指的是?
    c# 中的索引
    介绍如何使用C#中的委托
    C# 语法学习笔记
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12698110.html
Copyright © 2020-2023  润新知