CF446C DZY Loves Fibonacci Numbers 线段树

本文介绍了一种利用斐波那契数列的性质解决区间加法和查询区间和的问题。通过预处理斐波那契数列,并结合线段树数据结构,实现了高效的区间操作算法。

         给一个序列,接下来有若干条命令

1 L R : 给区间[L,R]之间的每个位置i,加上Fib(i-L+1),Fib(i)表示斐波那契数列第i项

2 L R : 返回区间[L,R]的区间和。

         利用斐波那契数列的两个性质,若一个数列满足F(1)=a,F(2)=b,Fi=Fi-2+F(i-1),则有F(n)=a*Fib(n-2)+b*Fib(n-1),且F的前N项和等于F(n+2)-F(2)。

可以发现,对于任何一个形同斐波那契的序列,只要知道前两项,就可以O(1)求出第N项以及前K项和,这样再每次1命令的时候,直接给要修改的区间标上要增加的斐波那契数列的前两项就行,维护子树的时候左子树标记不变,右子树根据左子树中修改的数量,更新标记即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r
using namespace std;
typedef long long ll;
const int maxn=300000+30;
const ll mod=1e9+9;
ll fib[maxn];
int n,m;
struct Mark
{
    ll a,b;
    Mark(){}
    Mark(ll x,ll y)
    {
        a=x; b=y;
    }
};
ll F(int x,ll a,ll b)
{
    return (fib[x-2]%mod*a%mod+fib[x-1]%mod*b%mod)%mod;
}
ll add(ll x,ll y)
{
	x+=y%mod;
	x=(x%mod+mod)%mod; 
	return x;
}
struct segmenttree
{
    Mark mark[maxn<<2];
    ll sum[maxn<<2];
    void init()
    {
        memset(mark,0,sizeof mark);
        memset(sum,0,sizeof sum);
    }
    void pushup(int id)
    {
	sum[id]=add(sum[id<<1|1],sum[id<<1]);

    }
    void pushdown(int id,int len)
    {
        if (mark[id].a==0 && mark[id].b==0) return;
	mark[id<<1].a=add(mark[id<<1].a,mark[id].a);
	mark[id<<1].b=add(mark[id<<1].b,mark[id].b);
	int midd=len-len/2;
	sum[id<<1]=add(sum[id<<1],add(F(midd+2,mark[id].a,mark[id].b),-mark[id].b));

        ll na=F(midd+1,mark[id].a,mark[id].b);
        ll nb=F(midd+2,mark[id].a,mark[id].b);
        mark[id<<1|1].a=add(mark[id<<1|1].a,na);
        mark[id<<1|1].b=add(mark[id<<1|1].b,nb);
	sum[id<<1|1]=add(sum[id<<1|1],add(F(len/2+2,na,nb),-nb));
        mark[id].a=mark[id].b=0;
        pushup(id);
    }
    void updata(int L,int R,int id,int l,int r,ll a,ll b)
    {
        int m=(l+r)>>1;
        int len=r-l+1;
        if (L==l && R==r)
        {
            mark[id].a=add(mark[id].a,a);
            mark[id].b=add(mark[id].b,b);
	    sum[id]=add(sum[id],add(F(len+2,a,b),-b));
            return;
        }
	pushdown(id,len);
        ll na,nb;
        if (R<=m)
        {
            updata(L,R,lson,a,b);
        }
        else if (L>m)
        {
            updata(L,R,rson,a,b);
        }
        else
        {
            na=F(m-L+1+1,a,b);
            nb=F(m-L+1+2,a,b);
            updata(L,m,lson,a,b);
            updata(m+1,R,rson,na,nb);
        }
        pushup(id);
    }
    ll query(int L,int R,int id,int l,int r)
    {
        if (L==l && R==r) return sum[id];
        int m=(l+r)>>1;
        pushdown(id,r-l+1);

        if (R<=m) return query(L,R,lson);
        else if (L>m) return query(L,R,rson);
        else return query(L,m,lson)+query(m+1,R,rson);
    }
}sgt;
void init()
{
    fib[0]=0;
    fib[1]=fib[2]=1;
    for (int i=3; i<maxn; i++)
    fib[i]=fib[i-1]+fib[i-2],fib[i]%=mod;
}
ll a[maxn];
ll sum[maxn];
int main()
{
    init();
//freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        sgt.init();
        memset(sum,0,sizeof sum);
        for (int i=1; i<=n; i++) scanf("%I64d",&a[i]);
        sum[0]=0;
        for (int i=1; i<=n; i++)
        sum[i]=sum[i-1]+a[i],sum[i]%=mod;
        int x,y,z;
        for (int i=0; i<m; i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            if (x==1)
            {
                sgt.updata(y,z,1,1,n,1,1);
            }
            else
            {
		    ll tmp=add(sum[z],-sum[y-1]);
                cout<<(sgt.query(y,z,1,1,n)+tmp)%mod<<endl;
            }
        }
    }
    return 0;
}



# CF446C DZY Loves Fibonacci Numbers ## 题目描述 斐波那契数列 $f_n$ 由以下递推式定义: - $f_1=f_2=1$ - $f_n=f_{n-1}+f_{n-2}\;(n>2)$ DZY 很喜欢斐波那契数列,它给了你 $n$ 个整数 $a_1,a_2,\cdots,a_n$. 你需要执行 $m$ 个操作,操作分两种: - `1 l r`:对所有 $l\le i\le r$,将 $a_i$ 加上 $f_{i-l+1}$. - `2 l r`:求 $a_l\sim a_r$ 的和,对 $10^9+9$ 取模. ## 输入格式 第一行两个整数 $n,m$. 第二行 $n$ 个整数 $a_1,a_2,\cdots,a_n$. 接下来 $m$ 行,每行三个整数表示一个操作. ## 输出格式 对每个 $2$ 操作,一行一个整数表示答案. ## 输入输出样例 #1 ### 输入 #1 ``` 4 4 1 2 3 4 1 1 4 2 1 4 1 2 4 2 1 3 ``` ### 输出 #1 ``` 17 12 ``` ## 说明/提示 $1\le n,m\le 3\times 10^5$ $1\le a_i\le 10^9$ 标称: ```cpp #include<cstdio> #include<cctype> #define pprint(x) ::print(x),putchar(' ') #define fprint(x) ::print(x),putchar('\n') using namespace std; inline long long read() { long long x = 0;int f = 1; char ch = getchar(); for(;!isdigit(ch);ch = getchar()) if(ch == '-') f = -1; for(;isdigit(ch);ch = getchar()) x = x * 10 + (ch ^ 48); return x * f; } void print(long long x) { if(x < 0) x = -x,putchar('-'); if(x > 9) print(x / 10); putchar(x % 10 + '0'); } const int N = 300010,mod = 1000000009,q1 = 691504013,q2 = 308495997,Inv = 276601605; long long qpow(long long a,int b) { long long ans = 1; while(b) { if(b & 1) ans = ans * a % mod; b >>= 1,a = a * a % mod; } return ans; } long long Mod(long long a) { if(a > mod) a -= mod; else if(a < 0) a += mod; return a; } int n,m; struct Seg_Tree { long long q,inv,m[N]; struct tree { int l,r; long long sum,lz; }t[N << 2]; #define ls now << 1 #define rs now << 1 | 1 void build(int now,int l,int r) { t[now].l = l,t[now].r = r; t[now].sum = t[now].lz = 0; if(l == r) return; int mid = l + r >> 1; build(ls,l,mid),build(rs,mid + 1,r); } void init(int Q) { q = Q,inv = qpow(q - 1,mod - 2); m[1] = q; for(int i = 2;i <= n;i++) m[i] = m[i - 1] * q % mod; build(1,1,n); } void pusha(int now,long long a) { int l = t[now].l,r = t[now].r; t[now].lz = Mod(t[now].lz + a); t[now].sum = (t[now].sum + Mod(a * m[r - l + 1] % mod - a) * inv) % mod; } void pushdown(int now) { if(t[now].lz) { int l = t[now].l,r = t[now].r,mid = l + r >> 1; pusha(ls,t[now].lz); pusha(rs,t[now].lz * m[mid - l + 1] % mod); t[now].lz = 0; } } void pushup(int now) { t[now].sum = Mod(t[ls].sum + t[rs].sum); } void update(int now,int l,int r,int a) { if(t[now].l == l && t[now].r == r) { pusha(now,a); return; } pushdown(now); int mid = t[now].l + t[now].r >> 1; if(r <= mid) update(ls,l,r,a); else if(l > mid) update(rs,l,r,a); else update(ls,l,mid,a),update(rs,mid + 1,r,a * m[mid - l + 1] % mod); pushup(now); } long long query(int now,int l,int r) { if(t[now].l == l && t[now].r == r) return t[now].sum; pushdown(now); int mid = t[now].l + t[now].r >> 1; if(r <= mid) return query(ls,l,r); else if(l > mid) return query(rs,l,r); else return Mod(query(ls,l,mid) + query(rs,mid + 1,r)); pushup(now); } #undef ls #undef rs }; Seg_Tree t1,t2; long long sum[N]; int main() { n = read(),m = read(); for(int i = 1;i <= n;i++) sum[i] = Mod(sum[i - 1] + read()); t1.init(q1),t2.init(q2); while(m--) { int op = read(),l = read(),r = read(); if(op == 1) t1.update(1,l,r,q1),t2.update(1,l,r,q2); else { long long a = t1.query(1,l,r); long long b = t2.query(1,l,r); a = Mod(a - b) * Inv % mod; fprint(Mod(Mod(a - sum[l - 1]) + sum[r]) % mod); } } return 0; } ``` 下面代码为什么WA了 ```cpp #include <bits/stdc++.h> using namespace std; const int N = 3e5 + 50; const int mod = 1e9 + 9; const int inv2 = (mod + 1) / 2; const int qr5 = 383008016; const int q1 = 1ll * (1 + qr5) * inv2 % mod; const int q2 = 1ll * (1 - qr5 + mod) * inv2 % mod; int n, m, a[N], s[N]; int qpow(int a, int k) { int res = 1; while (k) { if (k & 1) res = 1ll * res * a % mod; a = 1ll * a * a % mod; k >>= 1; } return res; } struct SegmentTree { int pw[N], inv; int sum[N << 2], tag[N << 2]; #define ls(cur) cur << 1 #define rs(cur) cur << 1 | 1 explicit SegmentTree(int q) { pw[0] = 1; for (int i = 1; i < N; i++) pw[i] = 1ll * pw[i - 1] * q % mod; inv = qpow(q - 1, mod - 2); } void pushup(int cur) { sum[cur] = (sum[ls(cur)] + sum[rs(cur)]) % mod; } void update(int cur, int l, int r, int a) { sum[cur] = (sum[cur] + 1ll * (pw[r - l + 1] - 1) * inv % mod * a) % mod; tag[cur] = (tag[cur] + a) % mod; } void pushdown(int cur, int l, int r) { if (tag[cur]) { int mid = l + r >> 1; update(ls(cur), l, mid, tag[cur]); update(rs(cur), mid + 1, r, 1ll * tag[cur] * pw[mid - l + 1] % mod); tag[cur] = 0; } } void add(int cur, int l, int r, int L, int R, int a) { if (L == l && r == R) { update(cur, l, r, a); return ; } pushdown(cur, l, r); int mid = l + r >> 1; // if (L <= mid) // add(ls(cur), l, mid, L, mid, a); // if (mid + 1 <= R) // add(rs(cur), mid + 1, r, mid + 1, R, 1ll * a * pw[max(0, mid - L + 1)] % mod); if (R <= mid) add(ls(cur), l, mid, L, R, a); else if (L > mid) add(rs(cur), mid + 1, r, L, R, a); else { add(ls(cur), l, mid, L, mid, a); add(rs(cur), mid + 1, r, mid + 1, R, 1ll * a * pw[mid - L + 1] % mod); } pushup(cur); } int query(int cur, int l, int r, int L, int R) { if (L <= l && r <= R) return sum[cur]; pushdown(cur, l, r); int mid = l + r >> 1; int res = 0; if (L <= mid) res += query(ls(cur), l, mid, L, R); if (mid + 1 <= R) res += query(rs(cur), mid + 1, r, L, R); return res % mod; } } t1(q1), t2(q2); int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i]; s[i] = (s[i - 1] + a[i]) % mod; } int inv = qpow(qr5, mod - 2); for (int opt, l, r; m--; ) { cin >> opt >> l >> r; if (opt == 1) { t1.add(1, 1, n, l, r, q1); t2.add(1, 1, n, l, r, q2); } else { int ans = t1.query(1, 1, n, l, r) - t2.query(1, 1, n, l, r) + mod; cout << (1ll * ans * inv + s[r] - s[l - 1] + mod) % mod << '\n'; } } return 0; } ```
最新发布
12-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值