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

来源:互联网 发布:python遍历json对象 编辑:程序博客网 时间:2024/06/03 18:05

题目: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)|1int 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\n", query(1, x, y));}}return 0;}


0 0
原创粉丝点击