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
  • 相关阅读:
    SPOJ SAMER08A
    SPOJ TRAFFICN
    CS Academy Set Subtraction
    CS Academy Bad Triplet
    CF Round 432 C. Five Dimensional Points
    CF Round 432 B. Arpa and an exam about geometry
    SPOJ INVCNT
    CS Academy Palindromic Tree
    身体训练
    简单瞎搞题
  • 原文地址:https://www.cnblogs.com/wmrv587/p/6188801.html
Copyright © 2011-2022 走看看