ZJOI2017 树状数组

题解

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

以上.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值