ZJOI2017 树状数组
2017-03-25 12:00
330 查看
题解
可以注意到,假的树状数组实际上是求后缀和。那么对于每个询问,真的树状数组查询的和是[l,r],假的查询的和是[l−1,r−1],它们的区别只有l−1和r这两个端点。考虑用一个树套树维护这个东西。第一维是左端点,第二维是右端点。
对于每个修改操作,都在对应地区间上打上保持不变的概率标记。
现在问题是如何合并两个保持不变的概率的标记。设两个概率为别为p1,p2
那么最终合并起来的概率就是p1×p2+(1−p1)×(1−p2),即都不变的概率+都变的概率。
需要特殊处理一下l−1=0的情况。
时间复杂度:O(nlog2n)
SRC
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std ; #define N 100000 + 10 typedef long long ll ; const int MO = 998244353 ; struct Tree { int Son[2] ; int Val ; } T[390*N] ; int Root[4*N] ; int n , m , Cnt ; int ret ; inline int Read() { int ret = 0 ; char ch = getchar() ; while ( ch < '0' || ch > '9' ) ch = getchar() ; while ( ch >= '0' && ch <= '9' ) { ret = ret * 10 + ch - '0' ; ch = getchar() ; } return ret ; } int Power( ll x , int k ) { ll s = 1 ; while ( k ) { if ( k & 1 ) s = s * x % MO ; x = x * x % MO ; k /= 2 ; } return s ; } int Merge( ll p1 , ll p2 ) { return (p1 * p2 % MO + ( -p1 + 1 + MO) * ( -p2 + 1 + MO) % MO) % MO ; } void Modify2( int &v , int l , int r , int x , int y , int mul ) { if ( !v ) v = ++ Cnt , T[v].Val = 1 ; if ( l == x && r == y ) { T[v].Val = Merge( T[v].Val , mul ) ; return ; } int mid = (l + r) >> 1 ; if ( y <= mid ) Modify2( T[v].Son[0] , l , mid , x , y , mul ) ; else if ( x > mid ) Modify2( T[v].Son[1] , mid + 1 , r , x , y , mul ) ; else { Modify2( T[v].Son[0] , l , mid , x , mid , mul ) ; Modify2( T[v].Son[1] , mid + 1 , r , mid + 1 , y , mul ) ; } } void Modify1( int v , int l , int r , int x1 , int y1 , int x2 , int y2 , int val ) { if ( l == x1 && r == y1 ) { Modify2( Root[v] , 1 , n , x2 , y2 , val ) ; return ; } int mid = (l + r) >> 1 ; if ( y1 <= mid ) Modify1( (v << 1) , l , mid , x1 , y1 , x2 , y2 , val ) ; else if ( x1 > mid ) Modify1( ((v << 1) | 1) , mid + 1 , r , x1 , y1 , x2 , y2 , val ) ; else { Modify1( (v << 1) , l , mid , x1 , mid , x2 , y2 , val ) ; Modify1( ((v << 1) | 1) , mid + 1 , r , mid + 1 , y1 , x2 , y2 , val ) ; } } void Search2( int v , int l , int r , int x ) { if ( !v ) return ; ret = Merge( ret , T[v].Val ) ; if ( l == r ) return ; int mid = (l + r) >> 1 ; if ( x <= mid ) Search2( T[v].Son[0] , l , mid , x ) ; else Search2( T[v].Son[1] , mid + 1 , r , x ) ; } void Search1( int v , int l , int r , int x , int y ) { if ( Root[v] ) Search2( Root[v] , 1 , n , y ) ; if ( l == r ) return ; int mid = (l + r) >> 1 ; if ( x <= mid ) Search1( (v << 1) , l , mid , x , y ) ; else Search1( ((v << 1) | 1) , mid + 1 , r , x , y ) ; } int main() { freopen( "bit.in" , "r" , stdin ) ; freopen( "bit.out" , "w" , stdout ) ; n = Read() , m = Read() ; for (int i = 1 ; i <= m ; i ++ ) { int op = Read() , l = Read() , r = Read() ; if ( op == 1 ) { int t = Power( r - l + 1 , MO - 2 ) ; int p = t , tmp = ( -p + 1 + MO) ; if ( l > 1 ) Modify1( 1 , 0 , n , 1 , l - 1 , l , r , tmp ) ; if ( r < n ) Modify1( 1 , 0 , n , l , r , r + 1 , n , tmp ) ; p = p * 2 > MO ? p * 2 % MO : p * 2 ; Modify1( 1 , 0 , n , l , r , l , r , ( -p + 1 + MO) ) ; if ( l > 1 ) Modify1( 1 , 0 , n , 0 , 0 , 1 , l - 1 , 0 ) ; if ( r < n ) Modify1( 1 , 0 , n , 0 , 0 , r + 1 , n , 0 ) ; p = 1ll * (r - l) * t % MO ; Modify1( 1 , 0 , n , 0 , 0 , l , r , ( -p + 1 + MO) ) ; } else { ret = 1 ; Search1( 1 , 0 , n , l - 1 , r ) ; printf( "%d\n" , ret ) ; } } return 0 ; }
以上.
相关文章推荐
- UOJ#291. 【ZJOI2017】树状数组
- BZOJ4785 [Zjoi2017]树状数组
- [Zjoi2017]bzoj4785 树状数组
- BZOJ4785: [Zjoi2017]树状数组
- 4785: [Zjoi2017]树状数组
- [BZOJ4785][ZJOI2017]树状数组(概率+二维线段树)
- BZOJ4785: [Zjoi2017]树状数组
- bzoj4785: [Zjoi2017]树状数组
- ●洛谷P3688 [ZJOI2017]树状数组
- bzoj4785 [Zjoi2017]树状数组
- 【ZJOI2017】树状数组
- [ZJOI2017]树状数组
- bzoj4785 UOJ #291 ZJOI2017 Day1 树状数组
- BZOJ4785 [Zjoi2017]树状数组
- [我可能是个ZZ啊] UOJ #291 【ZJOI2017】树状数组
- 【ZJOI2017 Round2练习&BZOJ4827】D1T3 gift(FFT)
- 【游记】ZJOI 2017 Day2 #1
- 【ZJOI2017 Round1练习】D2T2 iqtest(排列组合)
- 【ZJOI2017 Round1练习&BZOJ4774】D3T2 road(斯坦纳树,状压DP)
- 【ZJOI2017 Round1练习】D8T3 stone(NIM)