codeforces 718C Sasha and Array
阿新 • • 發佈:2018-11-06
線段樹維護矩陣資訊。。一定要把初值都賦好。。。
因為矩陣具有結合律,所以可以把子矩陣相加作為上一層的矩陣,對於更新的加值x,先線上段樹外將轉移矩陣自乘x次,
再新增到線段樹裡。主要是碼的準確。。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define mode 1000000007 using namespace std; typedef unsigned long long ll; void read(ll &x) { int f=1;x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} x*=f; } struct node { ll f[3][3]; }cs; struct Tree { node val,laz; }tr[100005*4]; node operator*(node a,node b) { node as; for(int i=1;i<=2;++i) { for(int j=1;j<=2;++j) { as.f[i][j]=0; for(int k=1;k<=2;++k) { as.f[i][j]+=a.f[i][k]*b.f[k][j]%mode; as.f[i][j]%=mode; } } } return as; } node ksm(node x,ll y) { node www; www.f[1][1]=1;www.f[1][2]=0; www.f[2][1]=0;www.f[2][2]=1; while(y) { if(y%2==1)www=www*x; y=y/2;x=x*x; } return www; } node gett(ll x) { if(x==2) { node yu; yu.f[1][1]=yu.f[2][1]=1;yu.f[1][2]=yu.f[2][2]=0; return yu; } if(x==1) { node yu; yu.f[1][1]=1;yu.f[2][1]=0;yu.f[1][2]=yu.f[2][2]=0; return yu; } node ww; ww.f[1][1]=1,ww.f[1][2]=0,ww.f[2][1]=1,ww.f[2][2]=0; return ksm(cs,x-2)*ww; } void pushup(int rt) { tr[rt].val.f[1][1]=(tr[rt<<1].val.f[1][1]+tr[rt<<1|1].val.f[1][1])%mode; tr[rt].val.f[1][2]=(tr[rt<<1].val.f[1][2]+tr[rt<<1|1].val.f[1][2])%mode; tr[rt].val.f[2][1]=(tr[rt<<1].val.f[2][1]+tr[rt<<1|1].val.f[2][1])%mode; tr[rt].val.f[2][2]=(tr[rt<<1].val.f[2][2]+tr[rt<<1|1].val.f[2][2])%mode; } void biuld(int l,int r,int rt) { tr[rt].laz.f[1][1]=1;tr[rt].laz.f[1][2]=0; tr[rt].laz.f[2][1]=0;tr[rt].laz.f[2][2]=1; if(l==r) { ll xx; read(xx); tr[rt].val=gett(xx); return; } int mid=(l+r)/2; biuld(l,mid,rt<<1); biuld(mid+1,r,rt<<1|1); pushup(rt); } void pushdown(int rt) { //if(tr[rt].laz) tr[rt<<1].val=tr[rt].laz*tr[rt<<1].val; tr[rt<<1|1].val=tr[rt].laz*tr[rt<<1|1].val; tr[rt<<1].laz=tr[rt].laz*tr[rt<<1].laz; tr[rt<<1|1].laz=tr[rt].laz*tr[rt<<1|1].laz; tr[rt].laz.f[1][1]=1;tr[rt].laz.f[1][2]=0; tr[rt].laz.f[2][1]=0;tr[rt].laz.f[2][2]=1; } void insert(int L,int R,int rt,int l,int r,node v) { if(L<=l&&r<=R) { tr[rt].val=v*tr[rt].val; tr[rt].laz=v*tr[rt].laz; return; } pushdown(rt); int mid=(l+r)/2; if(L<=mid)insert(L,R,rt<<1,l,mid,v); if(R>mid)insert(L,R,rt<<1|1,mid+1,r,v); pushup(rt); } ll query(int L,int R,int rt,int l,int r) { if(L<=l&&r<=R)return tr[rt].val.f[1][1]; pushdown(rt); int mid=(l+r)/2; if(R<=mid)return query(L,R,rt<<1,l,mid)%mode; else if(L>mid)return query(L,R,rt<<1|1,mid+1,r)%mode; else return (query(L,R,rt<<1,l,mid)+query(L,R,rt<<1|1,mid+1,r))%mode; } ll n,m,opt,l1,r1;ll po1; int main() { read(n);read(m); cs.f[1][1]=1,cs.f[1][2]=1,cs.f[2][1]=1;cs.f[2][2]=0; biuld(1,n,1); for(int i=1;i<=m;++i) { read(opt); if(opt==2) { read(l1);read(r1); printf("%I64d\n",query(l1,r1,1,1,n)); }else { read(l1);read(r1);read(po1); node wq=ksm(cs,po1); insert(l1,r1,1,1,n,wq); } } return 0; }