ZOJ 3772 Calculate the Function (好题,线段树) ZOJ 1671

我想说,这个题真的很好很好,感谢出题人让我再一次见识了..............


ZOJ 3772 Calculate the Function (好题,线段树) ZOJ 1671_第1张图片

typedef long long LL  ;

const   int  Mod = 1000000007 ;

struct  Mat{
        LL a[2][2] ;
        Mat(){
             memset(a , 0 , sizeof(a)) ;
        }
        Mat(LL a01){
             a[0][0] = 1   , a[0][1] = a01 ;
             a[1][0] = 1   , a[1][1] = 0   ;
        }
        Mat operator * (const Mat &other){
             Mat ans ;
             for(int i = 0 ; i < 2 ; i++){
                for(int j = 0 ; j < 2 ; j++){
                   for(int k = 0 ; k < 2 ; k++){
                          ans.a[i][j] = (ans.a[i][j] + a[i][k] * other.a[k][j]) % Mod ;
                    }
                }
             }
             return ans ;
        }
};

const  int Max_N =  100008  ;

Mat sum[Max_N<<2] ;
LL  x[Max_N] ;
int N ;

void  make_tree(int L , int R , int root){
      if(L == R){
           sum[root] = Mat(x[L]) ;
           return ;
      }
      int mid = (L + R) >> 1 ;
      make_tree(L , mid , root<<1) ;
      make_tree(mid+1 , R , root<<1|1) ;
      sum[root] = sum[root<<1|1] * sum[root<<1] ;
}

Mat  query(int l , int r  , int L , int R , int root){
     if(l <= L && R <= r)
         return sum[root] ;
     int mid = (L + R) >> 1 ;
     if(r <= mid)
          return query(l , r , L , mid , root<<1) ;
     else if(l > mid)
          return query(l , r , mid+1 , R , root<<1|1) ;
     else
          return query(l , r , mid+1 , R , root<<1|1) *  query(l , r , L , mid , root<<1) ;
}

LL   Ans(int  L , int R){
     if(L > R)
        swap(L , R) ;
     if(R == L || R == L + 1)
        return x[R] % Mod ;
     Mat m = query(L+2 , R , 1 , N , 1) ;
     return (m.a[0][0] * x[L+1] + m.a[0][1] * x[L]) % Mod ;
}

int main(){
    int T , M , i , l , r ;
    cin>>T ;
    while(T--){
          scanf("%d%d" ,&N ,&M) ;
          for(i = 1 ; i <= N ; i++)
              scanf("%lld" , &x[i]) ;
          make_tree(1 , N , 1) ;
          while(M--){
              scanf("%d%d" ,&l ,&r) ;
              printf("%lld\n" , Ans(l ,r)) ;
          }
    }
    return  0 ;
}


zoj  1671   

int   Mod ;

struct  Mat{
        int  elem[3][3] ;
        Mat(){
             memset(elem , 0 , sizeof(elem)) ;
        }
        void DiaOne(){
             elem[1][1] = elem[2][2] = 1 ;
        }
        void read(){
             scanf("%d%d%d%d" , &elem[1][1] ,&elem[1][2] , &elem[2][1] , &elem[2][2])  ;
        }
        void out(){
             printf("%d %d\n%d %d\n" , elem[1][1] ,elem[1][2] , elem[2][1] , elem[2][2])  ;
        }
};

Mat  operator * (Mat a , Mat b){
     Mat s ;
     int i , j ,  k  ;
     for(i = 1 ; i <= 2 ; i++){
        for(j = 1 ; j <= 2 ; j++){
            if(a.elem[i][j] == 0) continue ;
            for(k = 1 ; k <= 2 ; k++){
                s.elem[i][k] += a.elem[i][j] * b.elem[j][k] ;
                s.elem[i][k] %= Mod ;
            }
        }
     }
     return s ;
}

const  int  Max_N = 30008  ;
Mat sum[Max_N<<2]  , x[Max_N] ;

void  up(int t){
      sum[t] = sum[t<<1] * sum[t<<1|1] ;
}

void  make(int L , int R , int t){
      if(L == R){ sum[t] = x[L] ; return ;}
      int M = (L + R) >> 1 ;
      make(L , M , t<<1) ;
      make(M+1 , R , t<<1|1) ;
      up(t) ;
}

Mat  query(int l , int r , int L , int R , int t ){
     if(l <= L && R <= r)  return sum[t] ;
     int  M = (L + R) >> 1 ;
     Mat s ; s.DiaOne() ;
     if(l <= M) s = s * query(l , r , L , M , t<<1) ;
     if(r > M)  s = s * query(l , r , M+1 , R , t<<1|1) ;
     return s ;
}

int  main(){
     int i , n , m ,  l , r , T = 0 ;
     while(scanf("%d%d%d" ,&Mod, &n ,&m) != EOF ){
          for(i = 1 ; i <= n ; i++)  x[i].read() ;
          make(1 , n , 1) ;
          while(m--){
               scanf("%d%d" ,&l ,&r) ;
               if(T++ > 0) puts("") ;
               query(l , r , 1 , n , 1).out() ;
          }
     }
     return 0 ;
}







你可能感兴趣的:(ZOJ 3772 Calculate the Function (好题,线段树) ZOJ 1671)