習題:Sasha and Array(線段樹)
阿新 • • 發佈:2020-08-24
題目
思路
看見區間操作比較容易聯想到線段樹
考慮怎麼對於一個節點進行快速計算
對於葉子節點,存下\(f_{a_i-1},f_{a_i}\),每一個節點表示\(\sum_{i=l}^{r}f_{a_i-1},\sum_{i=l}^{r}f_{a_i}\)
考慮對\(a_l到a_r\)進行加\(x\)的操作,其實也就相當於他們合起來之後再進行操作,因為\(f_i=f_{i-1}+f_{i-2}\)
我們將所有的\(f_{i-1}\)看做一個整體,\(f_{i-2}\)看做一個整體,
之後就是快速冪的事情了
程式碼
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int mod=1e9+7; namespace IO { void read(int &x) { x=0; int f=1; char c=getchar(); while('0'>c||c>'9') { if(c=='-') f=-1; c=getchar(); } while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); } x*=f; } void read(long long &x) { x=0; int f=1; char c=getchar(); while('0'>c||c>'9') { if(c=='-') f=-1; c=getchar(); } while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); } x*=f; } void write(int x) { if(x<10) putchar(x+'0'); else { write(x/10); putchar(x%10+'0'); } } void write(long long x) { if(x<10) putchar(x+'0'); else { write(x/10); putchar(x%10+'0'); } } } namespace lst { struct mat { int n,m; long long a[3][3]; mat() { n=m=0; memset(a,0,sizeof(a)); } friend mat operator + (const mat &a,const mat &b) { mat c; c.n=a.n; c.m=a.m; for(int i=1;i<=a.n;i++) for(int j=1;j<=a.m;j++) c.a[i][j]=(a.a[i][j]+b.a[i][j])%mod; return c; } friend mat operator * (const mat &a,const mat &b) { mat c; c.n=a.n; c.m=b.m; for(int i=1;i<=a.n;i++) for(int k=1;k<=a.m;k++) for(int j=1;j<=b.m;j++) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod; return c; } void pr() { for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cout<<a[i][j]<<' '; cout<<endl; } } }bas,now,acc; struct tree { int l,r; mat f;//f_{x-1},f_{x} mat lazy; }tre[400005]; mat qkpow(mat a,long long b) { if(b==0) return bas; if(b==1) return a; mat t=qkpow(a,b/2); t=t*t; if(b%2==1) t=t*a; return t; } void push_down(int k) { tre[k<<1].f=tre[k].lazy*tre[k<<1].f; tre[k<<1].lazy=tre[k].lazy*tre[k<<1].lazy; tre[k<<1|1].f=tre[k].lazy*tre[k<<1|1].f; tre[k<<1|1].lazy=tre[k].lazy*tre[k<<1|1].lazy; tre[k].lazy=bas; } void build(int l,int r,int k) { tre[k].l=l; tre[k].r=r; tre[k].lazy=bas; if(l==r) { int x; cin>>x; tre[k].f.n=2; tre[k].f.m=1; tre[k].f.a[1][1]=1; tre[k].f.a[2][1]=0; tre[k].f=qkpow(acc,x)*tre[k].f; return; } int mid=(l+r)>>1; build(l,mid,k<<1); build(mid+1,r,k<<1|1); tre[k].f=tre[k<<1].f+tre[k<<1|1].f; } void add(int l,int r,int k=1) { if(l>tre[k].r||tre[k].l>r) return; if(l<=tre[k].l&&tre[k].r<=r) { tre[k].f=now*tre[k].f; tre[k].lazy=now*tre[k].lazy; return; } push_down(k); add(l,r,k<<1); add(l,r,k<<1|1); tre[k].f=tre[k<<1].f+tre[k<<1|1].f; } long long ask(int l,int r,int k=1) { if(tre[k].l>r||l>tre[k].r) return 0; if(l<=tre[k].l&&tre[k].r<=r) return tre[k].f.a[2][1]; push_down(k); return (ask(l,r,k<<1)+ask(l,r,k<<1|1))%mod; } } using namespace IO; using namespace lst; int n,m; int opt,l,r; long long x; void init() { bas.n=bas.m=2; for(int i=1;i<=2;i++) bas.a[i][i]=1; acc.n=acc.m=2; acc.a[1][2]=acc.a[2][1]=acc.a[2][2]=1; } int main() { init(); cin>>n>>m; build(1,n,1); for(int i=1;i<=m;i++) { read(opt); read(l); read(r); if(opt==1) { read(x); now=qkpow(acc,x); add(l,r); } else { write(ask(l,r)); putchar('\n'); } } return 0; }