• Codeforces 446C —— DZY Loves Fibonacci Numbers(线段树)


    题目:DZY Loves Fibonacci Numbers

    题意比較简单,不解释了。

    尽管官方的题解也是用线段树,但还利用了二次剩余。

    可是我没有想到二次剩余,然后写了个感觉非常复杂度的线段树,还是mark一下吧。

    我是这样考虑这个问题的,首先准备三个数组F,G,K,功能后面解释。

    然后对它们有这样一个计算:

    F[0] = G[0] = 0;
    F[1] = 1; G[1] = 0;
    K[0] = 1;
    K[1] = 0;
    for(int i=2; i<N; i++){
    	F[i] = (F[i-1]+F[i-2])%mod;
    	G[i] = (G[i-1]+F[i-1])%mod;
    	K[i] = (K[i-1]+K[i-2])%mod;
    }

    对于一个斐波那契数列,依据递推式我们能够知道即使我们要从中间開始。仅仅要知道连续两项(隔一项也能够。这里不考虑)。就能够顺利推出后面的值。

    那么如果我们知道如今连续两项是v1,v2。那么从它们開始的第n项vn就是:K[n-1]*v1 + K[n]*v2(1)。

    同一时候以v1,v2開始的连续n项的和是:F[n]*v1 + G[n]*v2(2)。

    上面两个式子都是能够利用斐波那契数列本身的递推式推导得到的。

    那么如今对于题目,如果我们要更新的是[L,R]区间,一開始传进去的是v1,v2,

    假设如今须要改动子节点了,求出结点的中间值M。对于左边的区间我们知道v1和 v2照旧,关键是右边的须要又一次计算。

    右边的第一项在原来的序列里面应该是属于第M+2-L项,记为x,所以能够利用上面(1)求出右边開始的两项。

    当我们到达某个结点。它相应的区间和我们要改动的区间一样时,能够利用(2)直接将和加在原来的答案上面。

    懒惰标记也非常好做。用f1和f2同一时候维护v1和v2的增量。

    假如有两个序列1。1,2。3和2,3,5,8都加到了某个区间上去。

    那么懒惰标记维护之后就是f1=1+2=3,,f2=1+3=4,利用递推能够算出后面两项就是7和11,这也符合原先两个序列的叠加。

    完毕上面的工作,剩下的查询就是非经常规的求和了。

    最后在CF上面跑了1122MS,还算能够吧。

    #include<cstdio>
    #include<cstring>
    const int mod = 1000000009;
    const int N = 300010;
    typedef long long LL;
    #define lson o<<1
    #define rson (o<<1)|1
    int a[N], l[N<<2], r[N<<2];
    LL s[N<<2], f1[N<<2], f2[N<<2];
    bool f[N<<2];
    LL F[N], G[N], K[N];
    inline void in(int &x){
    	char c=getchar();
    	x = 0;
    	while(c<48 || c>57)	c=getchar();
    	while(c>=48 && c<=57){
    		x = x*10+c-48;
    		c = getchar();
    	}
    }
    void maintain(int o){
    	s[o] = (s[lson] + s[rson])%mod;
    }
    void build(int o, int ll, int rr){
    	l[o] = ll; r[o]=rr;
    	f[o] = 0;
    	if(ll<rr){
    		int m = (ll+rr)>>1;
    		build(lson, ll, m);
    		build(rson, m+1, rr);
    		maintain(o);
    	}
    	else{
    		s[o] = a[ll];
    	}
    }
    void update(int o, int ll, int rr, LL v1, LL v2);
    void pushdown(int o){
    	if(f[o]){
    		int m = (l[o]+r[o])>>1;
    		update(lson, l[o], m, f1[o], f2[o]);
    		int x = m + 1 - l[o];
    		LL t1 = (K[x]*f1[o]%mod + K[x+1]*f2[o]%mod )%mod;
    		LL t2 = (K[x+1]*f1[o]%mod + K[x+2]*f2[o]%mod )%mod;
    		update(rson, m+1, r[o], t1, t2);
    		f[o] = 0;
    	}
    }
    void update(int o, int ll, int rr, LL v1, LL v2){
    	if(l[o]==ll && r[o]==rr){
    		int len = rr-ll+1;
    		s[o] = (s[o] + F[len]*v1%mod + G[len]*v2%mod)%mod;
    		if(!f[o]){
    			f1[o] = v1;
    			f2[o] = v2;
    			f[o] = 1;
    		}
    		else{
    			f1[o] = (f1[o] + v1)%mod;
    			f2[o] = (f2[o] + v2)%mod;
    		}
    		return;
    	}
    	pushdown(o);
    	int m = (l[o]+r[o])>>1;
    	if(rr<=m)	update(lson, ll, rr, v1, v2);
    	else if(ll>m)	update(rson, ll, rr, v1, v2);
    	else{
    		update(lson, ll, m, v1, v2);
    		int x = m + 1 - ll;
    		LL t1 = (K[x]*v1%mod + K[x+1]*v2%mod)%mod;
    		LL t2 = (K[x+1]*v1%mod + K[x+2]*v2%mod)%mod;
    		update(rson, m+1, rr, t1, t2);
    	}
    	maintain(o);
    }
    LL query(int o, int ll, int rr){
    	if(l[o]==ll && r[o]==rr)	return s[o];
    	pushdown(o);
    	int m = (l[o]+r[o])>>1;
    	LL tmp=0;
    	if(rr<=m)	tmp = query(lson, ll, rr);
    	else if(ll>m)	tmp = query(rson, ll, rr);
    	else{
    		tmp = (query(lson, ll, m)+query(rson, m+1, rr))%mod;
    	}
    	if(tmp<0){
    		tmp = (tmp%mod + mod)%mod;
    	}
    	maintain(o);
    	return tmp;
    }
    int main(){
    	F[0] = G[0] = 0;
    	F[1] = 1; G[1] = 0;
    	K[0] = 1;
    	K[1] = 0;
    	for(int i=2; i<N; i++){
    		F[i] = (F[i-1]+F[i-2])%mod;
    		G[i] = (G[i-1]+F[i-1])%mod;
    		K[i] = (K[i-1]+K[i-2])%mod;
    	}
    
    	int n, m;
    	in(n); in(m);
    	for(int i=1; i<=n; i++)	in(a[i]);
    	build(1, 1, n);
    	int op, x, y;
    	while(m--){
    		in(op); in(x); in(y);
    		if(op&1){
    			update(1, x, y, 1, 1);
    		}
    		else{
    			printf("%I64d
    ", query(1, x, y));
    		}
    	}
    	return 0;
    }
    


  • 相关阅读:
    Leetcode#145 Binary Tree Postorder Traversal
    Leetcode#146 LRU Cache
    单引号和双引号的区别
    $* $@ $#
    pthread_detach
    pthread_join
    intent 启动activity、service的方法
    multicast based on udp
    ARM指令系统
    ARM寄存器
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/6852300.html
Copyright © 2020-2023  润新知