bzoj5515: [Zjoi2019]线段树(线段树)

博客介绍了如何解决Zjoi2019竞赛中的一道线段树问题,分析了线段树在处理部分操作与不操作情况下的策略。文章详细讨论了线段树节点被标记的概率,以及四种不同类型的区间更新情况,并提供了相应的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门
每次等价于一部分操作一部分不操作。
显然一个点被标记只可能是被直接标记或者祖先被标记,于是我们对于每一个节点
维护它被标记的概率与祖先被标记的概率。
把每个区间分类讨论更新即可。
有如下几种情况:
1.覆盖祖先但未覆盖自己
2. 直接覆盖当前点
3. 经过当前点继续在子树中修改
4. 修改到父亲处向兄弟子树走
5. 修改到非父亲祖先向兄弟子树走
然后用线段树维护即可。
详见代码
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
    static char buf[rlen],*ib,*ob;
    (ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
    return ib==ob?-1:*ib++;
}
inline int read(){
    int ans=0;
    char ch=gc();
    while(!isdigit(ch))ch=gc();
    while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
    return ans;
}
typedef long long ll;
const int mod=998244353,inv=(mod+1)/2,N=1e5+5;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline void Add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
int n,m,det=1;
namespace sgt{
    #define lc (p<<1)
    #define rc (p<<1|1)
    #define mid (T[p].l+T[p].r>>1)
    struct Node{int l,r,f,g,s,tf,tg;}T[N<<3];
    inline void pushup(int p){T[p].s=add(add(T[lc].s,T[p].f),T[rc].s);}
    inline void pf(int p,int v){T[p].f=mul(T[p].f,v),T[p].tf=mul(T[p].tf,v),T[p].s=mul(T[p].s,v);}
    inline void pg(int p,int v){T[p].g=mul(T[p].g,v),T[p].tg=mul(T[p].tg,v);}
    inline void pushdown(int p){
        if(T[p].tf^1)pf(lc,T[p].tf),pf(rc,T[p].tf),T[p].tf=1;
        if(T[p].tg^1)pg(lc,T[p].tg),pg(rc,T[p].tg),T[p].tg=1;
    }
    inline void build(int p,int l,int r){
        T[p].l=l,T[p].r=r,T[p].tf=T[p].tg=T[p].g=1,T[p].f=T[p].s=0;
        if(l==r)return;
        build(lc,l,mid),build(rc,mid+1,r);
    }
    inline void modify(int p){
        pushdown(p);
        Add(T[p].f,dec(det,T[p].g)),T[p].g=add(T[p].g,T[p].g);
        pf(lc,2),pg(lc,2),pf(rc,2),pg(rc,2),pushup(p);
    }
    inline void update(int p,int ql,int qr){
        pushdown(p);
        if(ql<=T[p].l&&T[p].r<=qr)return Add(T[p].f,det),pf(lc,2),pf(rc,2),pushup(p);
        Add(T[p].g,det);
        if(qr<=mid)return update(lc,ql,qr),modify(rc),pushup(p);
        if(ql>mid)return update(rc,ql,qr),modify(lc),pushup(p);
        update(lc,ql,qr),update(rc,ql,qr),pushup(p);
    }
    #undef lc
    #undef rc
    #undef mid
}
int main(){
    n=read(),m=read();
    sgt::build(1,1,n);
    for(ri op,l,r;m;--m){
        op=read();
        switch(op){
            case 1:{
                l=read(),r=read();
                sgt::update(1,l,r);
                det=add(det,det);
                break;
            }
            case 2:{
                cout<<sgt::T[1].s<<'\n';
                break;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值