zoj 3772 线段树--单点更新
2014-04-06 22:39
393 查看
转自:点击打开链接
题意:
给一个序列An
有m个询问,每个询问包括l和r
定义f(l) = a[l], f(l+1) = a[l+1], f(x)=f(x-1) + a[x] * f(x-2), x >= l + 2;
对每个询问,求f(r);
当x>=l+2时,
f(x)=f(x-1) + a[x]* f(x-2), 所以就有递推式
所以当r>=l+1时,
然后就可以先求出:
用线段树就可以在O(logn)的时间求出这个式子,不过线段树的每个节点保存的是一个矩阵
还有就是要注意矩阵乘的方向
总的复杂度是O(nlogn+mlogn)
WA注意用long long
AC代码如下:
题意:
给一个序列An
有m个询问,每个询问包括l和r
定义f(l) = a[l], f(l+1) = a[l+1], f(x)=f(x-1) + a[x] * f(x-2), x >= l + 2;
对每个询问,求f(r);
当x>=l+2时,
f(x)=f(x-1) + a[x]* f(x-2), 所以就有递推式
所以当r>=l+1时,
然后就可以先求出:
用线段树就可以在O(logn)的时间求出这个式子,不过线段树的每个节点保存的是一个矩阵
还有就是要注意矩阵乘的方向
总的复杂度是O(nlogn+mlogn)
WA注意用long long
AC代码如下:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define MOD 1000000007 struct Matrix{ long long num[2][2]; Matrix( int n ){ num[0][0] = 1; num[0][1] = n; num[1][0] = 1; num[1][1] = 0; } Matrix(){ memset( num, 0, sizeof( num ) ); } Matrix operator*( const Matrix &b ) const{ Matrix mm; for( int i = 0; i < 2; i++ ){ for( int j = 0; j < 2; j++ ){ mm.num[i][j] = 0; for( int k = 0; k < 2; k++ ){ mm.num[i][j] = ( mm.num[i][j] + ( num[i][k] % MOD ) * ( b.num[k][j] % MOD ) ) % MOD; } } } return mm; } }; Matrix m[400000]; long long num[110000]; int N, M; int lc( int root ){ return 2 * root; } int rc( int root ){ return 2 * root + 1; } void updata( int root ){ m[root] = m[rc(root)] * m[lc(root)]; } void built( int l, int r, int root ){ if( l == r ){ long long temp; scanf( "%lld", &temp ); Matrix tt( temp ); m[root] = tt; num[l] = temp; return; } int mid = ( l + r ) / 2; built( l, mid, lc( root ) ); built( mid + 1, r, rc( root ) ); updata( root ); } Matrix query( int L, int R, int l, int r, int root ){ if( L <= l && R >= r ){ return m[root]; } Matrix a, b; int mid = ( l + r ) / 2; if( L <= mid ) a = query( L, R, l, mid, lc( root ) ); if( R > mid ) b = query( L, R, mid + 1, r, rc( root ) ); if( L > mid ) return b; if( R <= mid ) return a; return b * a; } int main(){ int T; cin >> T; while( T-- ){ cin >> N >> M; built( 1, N, 1 ); for( int i = 1; i <= M; i++ ){ int l, r; scanf( "%d%d", &l, &r ); if( r - l <= 1 ){ cout << num[r] << endl; }else{ Matrix mm = query( l + 2, r, 1, N, 1 ); cout << ( num[l] % MOD * mm.num[0][1] % MOD + num[l+1] % MOD * mm.num[0][0] % MOD ) % MOD << endl;; } } } return 0; }
相关文章推荐
- zoj 3279 ants 线段树+单点更新+查询下标
- ZOJ - 1610 Count the Colors(线段树区间更新,单点查询)
- zoj (单点更新区间查询:线段树)
- zoj 3279 Ants (线段树单点更新)
- ZOJ 3886 Nico Number(线段树单点更新+找规律)
- ZOJ 3453 Doraemon's Sweet Bullet(线段树区间更新+单点更新+最值询问)
- ZOJ - 1610 Count the Colors (线段树单点查询 区间更新)
- zoj 3633 线段树单点更新 区间最大值
- ZOJ 5638——Prime Query——————【线段树区间更新,区间查询,单点更新】
- ZOJ 3279 Ants(线段树单点更新和查询)
- zoj-1610-Count the Colors-线段树-区域更新,单点查询
- zoj 3635 线段树 区间求位置 单点更新
- ZOJ 1484 HDU 1394 Minimum Inversion Number / 线段树单点更新
- hdu2795 Billboard(线段树单点更新)
- hdu4521 小明系列问题——小明序列(LIS变种 (线段树+单点更新解法))
- NYOJ 116 士兵杀敌(二)(线段树区间求和+单点更新)
- 线段树 hdu 1754 I Hate It 单点更新 区间求最值
- hdu 1394 Minimum Inversion Number(线段树之 单点更新求逆序数)
- hdu 1166线段树 单点更新 区间求和
- hdu2795Billboard(线段树单点更新 区间K值)