您的位置:首页 > 其它

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 ;
}


以上.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: