zoukankan      html  css  js  c++  java
  • 【CF316E3】Summer Homework

    题目描述

    By the age of three Smart Beaver mastered all arithmetic operations and got this summer homework from the amazed teacher:

    You are given a sequence of integers (a_{1},a_{2},...,a_{n}). Your task is to perform on it mm consecutive operations of the following type:

    1. For given numbers (x_{i}) and (v_{i}) assign value (v_{i}) to element (a_{x_i}).

    2. For given numbers (l_{i}) and (r_{i}) you've got to calculate sum (Sigma_{x=0}^{r_i-l_i}f_xa_{l_i+x}), where (f_{0}=f_{1}=1) and at (igeq 2) : (f_{i}=f_{i-1}+f_{i-2}).

    3. For a group of three numbers (l_{i}) (r_{i}) (d_{i}) you should increase value (a_{x}) by (d_{i}) for all (x) ((l_{i}<=x<=r_{i}))).

    Smart Beaver planned a tour around great Canadian lakes, so he asked you to help him solve the given problem.

    题目大意

    • 在这里,我们用 (f_i) 表示第 (i) 个斐波那契数 (f_0=1,f_1=1,f_i=f_{i-1}+f_{i-2}(ige 2))

    • 给定 (n) 个数的序列 (a)(m) 次操作。操作有三种:

      1. 1 x v:将 (a_x) 赋值为 (v)

      2. 2 l r:求 (sum_{x=0}^{r-l}(f_xcdot a_{l+x}) mod 10^9)

      3. 3 l r d:将 (a_lsim a_r) 加上 (d)

    • (1le n,mle 2 imes10^5)(0le a_i,v,dle 10^5)

    思路

    对于一个区间 ([l,r]),用线段树维护一个 (s_n),其中 (s_n=Sigma_{i=0}^{r-l}a_{l+i}f_{i+n}),即 ({f}) 从第 (n) 项开始与 ({a}) 对应相乘求和

    那么题中所求就是 (s_0),对于一个区间 seg,它的左右儿子是 lsonrson,那么有 (seg.s_n = lson.s_n+rson.s_{n+lson.len})

    同时,({s})({f}) 有相同的递推性质,即 (s_n=s_{n-1}+s_{n-2}),因为:

    (s_{n-1}+s_{n-2}=Sigma_{i=0}^{r-l}a_{l+i}f_{i+n-1}+Sigma_{i=0}^{r-l}a_{l+i}f_{i+n-2}=Sigma_{i=0}^{r-l}a_{l+i}(f_{i+n-1}+f_{i+n-2})=Sigma_{i=0}^{r-l}a_{l+i}f_{i+n}=s_n)

    那么只用线段树记录下 (s_0,s_1) ,就可递推出 (s_n)

    [s_2=s_0+s_1 ]

    [s_3=s_1+s_2=s_0+2s_1 ]

    [s_4=s_2+s_3=2s_0+3s_1 ]

    [s_5=s_3+s_4=3s_0+5s_1 ]

    [vdots ]

    [s_n=f_{n-2}s_0+f_{n-1}s_1 ]

    #include <algorithm>
    #include <cstdio>
    using namespace std;
    const int maxn = 2e5 + 10;
    const int mod = 1e9;
    int n,m,f[maxn] = { 1,1 },pre[maxn] = { 1,2 },laz[maxn<<2];
    struct func {
    	int s0,s1;
    	inline int s(int x) {
    		if (x == 0) return s0;
    		if (x == 1) return s1;
    		return (1ll*f[x-2]*s0%mod+1ll*f[x-1]*s1%mod)%mod;
    	}
    } t[maxn<<2];
    inline void pushup(int root,int l,int r) {
    	int mid = l+r>>1;
    	t[root].s0 = (t[root<<1].s0+t[root<<1|1].s(mid-l+1))%mod;
    	t[root].s1 = (t[root<<1].s1+t[root<<1|1].s(mid-l+2))%mod;
    }
    inline void pushdown(int root,int l,int r) {
    	int mid = l+r>>1;
    	if (laz[root]) {
    		(laz[root<<1] += laz[root])%= mod;
    		(laz[root<<1|1] += laz[root])%= mod;
    		(t[root<<1].s0 += 1ll*laz[root]*pre[mid-l]%mod) %= mod;
    		(t[root<<1|1].s0 += 1ll*laz[root]*pre[r-mid-1]%mod) %= mod;
    		(t[root<<1].s1 += 1ll*laz[root]*(pre[mid-l+1]-pre[0])%mod) %= mod;
    		(t[root<<1|1].s1 += 1ll*laz[root]*(pre[r-mid]-pre[0])%mod) %= mod;
    		laz[root] = 0;
    	}
    }
    inline void build(int l,int r,int root) {
    	if (l == r) {
    		scanf("%d",&t[root].s0);
    		t[root].s1 = t[root].s0;
    		return;
    	}
    	int mid = l+r>>1;
    	build(l,mid,root<<1);
    	build(mid+1,r,root<<1|1);
    	pushup(root,l,r);
    }
    inline void update(int l,int r,int ul,int ur,int root,int x) {
    	if (l > ur || r < ul) return;
    	if (ul <= l && r <= ur) {
    		laz[root] += x;
    		(t[root].s0 += 1ll*x*pre[r-l]%mod) %= mod;
    		(t[root].s1 += 1ll*x*(pre[r-l+1]-pre[0])%mod) %= mod;
    		return;
    	}
    	pushdown(root,l,r);
    	int mid = l+r>>1;
    	update(l,mid,ul,ur,root<<1,x);
    	update(mid+1,r,ul,ur,root<<1|1,x);
    	pushup(root,l,r);
    }
    inline func query(int l,int r,int ql,int qr,int root) {
    	if (ql <= l && r <= qr) return t[root];
    	pushdown(root,l,r);
    	int mid = l+r>>1;
    	if (mid < ql) return query(mid+1,r,ql,qr,root<<1|1);
    	else if (mid >= qr) return query(l,mid,ql,qr,root<<1);
    	else {
    		func ls = query(l,mid,ql,qr,root<<1),rs = query(mid+1,r,ql,qr,root<<1|1);
    		return (func){ (ls.s0+rs.s(mid-max(l,ql)+1))%mod,(ls.s1+rs.s(mid-max(l,ql)+2))%mod };
    	}
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	for (int i = 2;i <= n;i++) {
    		f[i] = (f[i-1]+f[i-2])%mod;
    		pre[i] = (pre[i-1]+f[i])%mod;
    	}
    	for (build(1,n,1);m--;) {
    		int op,l,r,d;
    		scanf("%d%d%d",&op,&l,&r);
    		if (op == 1) update(1,n,l,l,1,r-query(1,n,l,l,1).s0);
    		if (op == 2) printf("%d
    ",query(1,n,l,r,1).s0);
    		if (op == 3) {
    			scanf("%d",&d);
    			update(1,n,l,r,1,d);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Vue常用语法
    Vue--过滤器、指令、插件
    使用vue-cli创建项目
    electron Ctrl+滚轮事件 放大缩小
    axios 处理超时问题 记录
    electron 清除所有cookie记录
    electron用默认浏览器打开链接的3种实现方式
    electron 不支持Ctrl+滚动条放大缩小,自己动手做了一个react组件
    排序算法记录
    umi react 集成 spreadjs
  • 原文地址:https://www.cnblogs.com/lrj124/p/14357796.html
Copyright © 2011-2022 走看看