可以注意到,假的树状数组实际上是求后缀和。那么对于每个询问,真的树状数组查询的和是 [l,r] ,假的查询的和是 [l−1,r−1] ,它们的区别只有 l−1 和 r 这两个端点。
考虑用一个树套树维护这个东西。第一维是左端点,第二维是右端点。
对于每个修改操作,都在对应地区间上打上保持不变的概率标记。
现在问题是如何合并两个保持不变的概率的标记。设两个概率为别为 p1,p2
那么最终合并起来的概率就是 p1×p2+(1−p1)×(1−p2) ,即都不变的概率+都变的概率。
需要特殊处理一下 l−1=0 的情况。
时间复杂度: O(nlog2n)
#include
#include
#include
#include
#include
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 ;
}
以上.