题目: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; }