zoukankan      html  css  js  c++  java
  • CF719E(线段树+矩阵快速幂)

    题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作

    分析:线段树

       线段树的每个节点表示(f[i],f[i-1])这个数组

       因为矩阵的可加性,所以可以进行lazy操作

       我最开始的想法是每个节点lazy表示该区间下标加了多少,add表示该区间已经加的下标对应的矩阵乘积,这样更新lazy是O(1)的,算add是O(logn)的

       但是这样每次pushdown的时候,add下传总要多个log,会TLE

       更好的办法是lazy表示加的下标对应的矩阵乘积,这样虽然每次更新lazy是O(logn)的,但是pushdown的时候就是直接把(f[i],f[i-1])和lazy[2][2]乘起来了,是O(1)的

    代码:

      1 #include<bits/stdc++.h>
      2 const int maxn=1e5;
      3 const long long mod=1e9+7;
      4 int ch[maxn*2+50][2];
      5 long long sum[maxn*2+50][2],add[maxn*2+50][2][2],a[maxn+50];
      6 int len=0,n,m;
      7 void mer(long long a[2][2],long long b[2][2])
      8 {
      9     long long s[2][2];
     10     memset(s,0,sizeof(s));
     11     for(int i=0;i<2;++i)
     12         for(int j=0;j<2;++j)
     13             for(int k=0;k<2;++k)
     14                 s[i][j]=(s[i][j]+a[i][k]*b[k][j]%mod)%mod;
     15     for(int i=0;i<2;++i)
     16         for(int j=0;j<2;++j)
     17             a[i][j]=s[i][j];
     18 }
     19 void fib(long long num[2][2],long long x)
     20 {
     21     long long a[2][2]={{1,1},{1,0}};
     22     num[0][0]=1,num[0][1]=0,num[1][0]=0,num[1][1]=1;
     23     while(x)
     24     {
     25         if(x&1) mer(num,a);
     26         mer(a,a);
     27         x>>=1;
     28     }
     29 }
     30 void cal(long long sum[2],long long s[2][2])
     31 {
     32     long long x=(sum[0]*s[0][0]%mod+sum[1]*s[1][0]%mod)%mod;
     33     long long y=(sum[0]*s[0][1]%mod+sum[1]*s[1][1]%mod)%mod;
     34     sum[0]=x,sum[1]=y;
     35 }
     36 void pushdown(int k)
     37 {
     38     if(add[k][0][0]==1&&add[k][0][1]==0&&add[k][1][0]==0&&add[k][1][1]==1) return;
     39     //printf("A");
     40     //cal(sum[k],add[k]);
     41     int l=ch[k][0],r=ch[k][1];
     42     if(l) mer(add[l],add[k]),cal(sum[l],add[k]);
     43     if(r) mer(add[r],add[k]),cal(sum[r],add[k]);
     44     add[k][0][0]=1,add[k][0][1]=0,add[k][1][0]=0,add[k][1][1]=1;
     45 }
     46 void update(int k)
     47 {
     48     int l=ch[k][0],r=ch[k][1];
     49     //cal(sum[k],add[k]);
     50     //pushdown(k);
     51     for(int i=0;i<2;++i) sum[k][i]=(sum[l][i]+sum[r][i])%mod;
     52   //  if(k==2) printf("A : %d %d %lld %lld
    ",l,r,sum[l][0],sum[r][0]);
     53 }
     54 int build(int l,int r)
     55 {
     56     if(l>r) return 0;
     57     int mid=(l+r)>>1;
     58     int k=++len;
     59     add[k][0][0]=1,add[k][0][1]=0,add[k][1][0]=0,add[k][1][1]=1;
     60     if(l==r)
     61     {
     62         sum[k][0]=1,sum[k][1]=0;
     63         long long num[2][2];
     64         fib(num,a[l]-1);
     65         cal(sum[k],num);
     66         //printf("%d %d %d %d %d
    ",l,r,k,ch[k][0],ch[k][1]);
     67         return k;
     68     }
     69     ch[k][0]=build(l,mid);
     70     ch[k][1]=build(mid+1,r);
     71     update(k);
     72     return k;
     73    // printf("%d %d %d %d %d
    ",l,r,k,ch[k][0],ch[k][1]);
     74 }
     75 void make(int k,int l,int r,int x,int y,long long num[2][2])
     76 {
     77     if(l>r) return;
     78     if(l>y||r<x) return;
     79     if(x<=l&&y>=r)
     80     {
     81         mer(add[k],num);
     82         cal(sum[k],num);
     83         return;
     84     }
     85     int mid=(l+r)>>1;
     86     pushdown(k);
     87     if(l<=mid) make(ch[k][0],l,mid,x,y,num);
     88     if(r>mid) make(ch[k][1],mid+1,r,x,y,num);
     89     update(k);
     90 }
     91 long long query(int k,int l,int r,int x,int y)
     92 {
     93     if(l>r) return 0;
     94     if(l>y||r<x) return 0;
     95     if(x<=l&&y>=r)
     96     {
     97         return sum[k][0];
     98     }
     99     int mid=(l+r)>>1;
    100     pushdown(k);
    101     return (query(ch[k][0],l,mid,x,y)+query(ch[k][1],mid+1,r,x,y))%mod;
    102 }
    103 int main()
    104 {
    105 
    106     scanf("%d %d",&n,&m);
    107     for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
    108     build(1,n);
    109     //for(int i=1;i<=len;++i) printf("%d %lld %lld
    ",i,sum[i][0],sum[i][1]);
    110     //or(int i=1;i<=len;++i) printf("%d %lld %lld %lld %lld
    ",i,add[i][0][0],add[i][0][1],add[i][1][0],add[i][1][1]);
    111     for(int i=1;i<=m;++i)
    112     {
    113         int t,l,r;
    114         long long x;
    115         scanf("%d %d %d",&t,&l,&r);
    116         if(t==1)
    117         {
    118             scanf("%lld",&x);
    119             long long num[2][2];
    120             fib(num,x);
    121             make(1,1,n,l,r,num);
    122         }
    123         else printf("%lld
    ",query(1,1,n,l,r));
    124     }
    125     return 0;
    126 }
    View Code
  • 相关阅读:
    RedHat7安装NetCore环境并发布网站
    【WPF学习】第四十二章 透明
    细说枚举
    js获取ip地址,操作系统,浏览器版本等信息,可兼容
    js实现数据流(日志流,报警信息等)滚动展示,并分页(含实现demo)
    js实现点击copy,可兼容
    js实现htmlToWordDemo
    H5 web 存储之 Webstorage
    已发布的WEB项目,如何挂在服务器或者本机的IIS下
    Nuget打包没有注释显示
  • 原文地址:https://www.cnblogs.com/wmrv587/p/6188801.html
Copyright © 2011-2022 走看看