题目的大意是你需要维护一个序列a,有两种操作:
1.对于区间[l,r],对于l<=i<=r,ai+=f[i-l+1],f是斐波那契数列
2.查询区间[l,r]的和
很久以前在培训的时候写过,然而并不会做,后来一直拖到退役也没有搞懂,今天心血来潮研究了一下,发现还是比较简单的。
很明显,这道题我们需要用线段树来维护,因为有区间操作,所以我们需要打标记,但是我们知道,线段树的标记应该满足可传递性,显然直接打标记是错误的
我们进行一个推倒:
设a,b是斐波那契数列中连续的两项,那么之后的序列应该是这样的:
a , b , a+b , a+2b , 2a+3b , 3a+5b...
我们发现从第三项开始a的系数是1,1,2,3,5
b的系数是1,2,3,5
也就是说其后的第i项应该是:a*f[i-2]+b*f[i-1]
那么我们对其后的n项求一个和,那么就应该是:a*(f[1]+f[2]+f[3]+...+f[n-2])+b*(f[1]+f[2]+f[3]+...+f[n-1])
那么我们发现想要维护一个区间[l,r]的标记我们只需要维护a和b即可,其后的取决于区间的长度
比如我们标记了[l,r]
那当我们下传标记的时候应该怎么做呢?
[l,(l+r)>>1] 的a和b直接下传即可
[(l+r)>>1|1,r]的a和b就要变化了,因为这里的(l+r)>>1|1实际上是[l,r]的第(l+r)>>1|1-l+1项,所以a就是(l+r)>>1|1-l+1,b是a+1
这样就可以做到下标的传递了,每次标记直接相加即可。
这道题也就解决了,代码过几天再写。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<algorithm> 7 #define mod 1000000009 8 #define ll long long 9 using namespace std; 10 struct tree{ 11 int l,r; 12 ll taga,tagb; 13 ll sum; 14 }f[1200005]; 15 int n,m; 16 ll fib[300005],a[300005],sf[300005]; 17 void update(int i,int ta,int tb){ 18 int len=f[i].r-f[i].l+1; 19 //cout<<f[i].sum<<endl; 20 if(len>=2){ 21 ll tmp1=(ta*sf[len-2])%mod,tmp2=(tb*sf[len-1])%mod; 22 tmp1=(tmp1+tmp2)%mod; 23 //cout<<tmp1<<endl; 24 f[i].sum=(f[i].sum+tmp1)%mod; 25 f[i].sum=(f[i].sum+ta)%mod; 26 } 27 else{ 28 f[i].sum=(f[i].sum+ta)%mod; 29 f[i].sum=(f[i].sum+tb*(len-1))%mod; 30 } 31 //cout<<f[i].sum<<endl; 32 f[i].taga=(f[i].taga+ta)%mod; 33 f[i].tagb=(f[i].tagb+tb)%mod; 34 return ; 35 } 36 void pushup(int i){ 37 f[i].sum=(f[i<<1].sum+f[i<<1|1].sum)%mod; 38 return ; 39 } 40 void pushdown(int i){ 41 if(f[i].taga){ 42 update(i<<1,f[i].taga,f[i].tagb); 43 int mid=(f[i].r+f[i].l)>>1,len=(mid-f[i].l+1); 44 //if(len>=2){ 45 ll tmp1=((f[i].taga*fib[len-1])%mod+(f[i].tagb*fib[len])%mod)%mod; 46 ll tmp2=((f[i].taga*fib[len])%mod+(f[i].tagb*fib[len+1])%mod)%mod; 47 update(i<<1|1,tmp1%mod,tmp2%mod); 48 // } 49 //else update(i<<1|1,f[i].tagb,(f[i].taga+f[i].tagb)%mod); 50 f[i].taga=0;f[i].tagb=0; 51 return ; 52 } 53 else return ; 54 } 55 void build(int i,int left,int right){ 56 f[i].l=left;f[i].r=right; 57 if(left==right){ 58 f[i].sum=a[left]; 59 return ; 60 } 61 int mid=(left+right)>>1; 62 build(i<<1,left,mid);build(i<<1|1,mid+1,right); 63 pushup(i); 64 //cout<<f[i].sum<<f[i<<1].sum<<f[i<<1|1].sum<<endl; 65 return ; 66 } 67 void add(int i,int left,int right,int num){ 68 if(f[i].l==left&&f[i].r==right){ 69 update(i,fib[num],fib[num+1]); 70 return ; 71 } 72 pushdown(i); 73 int mid=f[i<<1].r,len=(mid-left+1); 74 if(right<=mid)add(i<<1,left,right,num); 75 else if(left>mid)add(i<<1|1,left,right,num); 76 else add(i<<1,left,mid,num),add(i<<1|1,mid+1,right,num+len); 77 pushup(i); 78 } 79 ll query(int i,int left,int right){ 80 if(f[i].l==left&&f[i].r==right)return f[i].sum; 81 pushdown(i); 82 int mid=(f[i].l+f[i].r)>>1; 83 if(right<=mid)return query(i<<1,left,right); 84 else if(mid<left)return query(i<<1|1,left,right); 85 else return (query(i<<1,left,mid)+query(i<<1|1,mid+1,right))%mod; 86 } 87 int main(){ 88 //freopen("input.txt","r",stdin); 89 fib[1]=1;fib[2]=1;sf[1]=1;sf[2]=2; 90 ios_base::sync_with_stdio(false); 91 cin.tie(0); 92 cin>>n>>m; 93 for(int i=1;i<=n;i++) 94 cin>>a[i]; 95 for(int i=3;i<=n+3;i++){ 96 fib[i]=(fib[i-1]+fib[i-2])%mod; 97 sf[i]=(sf[i-1]+fib[i])%mod; 98 } 99 build(1,1,n); 100 for(int i=1;i<=m;i++){ 101 int x,y,z; 102 cin>>x>>y>>z; 103 //cout<<"SSS"<<endl; 104 if(x==1)add(1,y,z,1); 105 else cout<<query(1,y,z)<<'\n'; 106 //cout<<"SSS"<<endl; 107 } 108 return 0; 109 }