[ZJOI2017]树状数组

题目描述

https://www.luogu.org/recordnew/lists?pid=P3688

题解

这道题其实就是问l-1和r相等的概率。

考虑一个修改操作[L,R],它可能对一下询问产生影响。

一个点在区间里,一个点不在。

两个点都在区间里。

对于第一种情况,把两个点的相等关系取反的概率为1/len。

对于第二种情况,把两个点取反的概率为2/len。

所以我们维护所有可能的二元组(x,y)和在两个点相等的概率。

例如当前概率为x,取反概率为y,那么相等的概率为x*(1-y)+y*(1-x)。

用树套树维护。

特判:可能有l=1的情况,所以我们再开一颗线段树维护这种情况。

代码(结构体大法好)

#include<iostream>
#include<cstdio>
#define N 100009
using namespace std;
typedef long long ll;
const int mod=998244353;
int n,m;
inline int rd(){
    int x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x; 
}
inline int merge(int x,int y){return (1ll*x*(1ll-y+mod)+1ll*y*(1ll-x+mod))%mod;}
inline int ni(int x){
    int y=mod-2,ans=1;
    while(y){
        if(y&1)ans=1ll*ans*x%mod;x=1ll*x*x%mod;y>>=1;
    }
    return ans;
}
struct deep_dark_fantasy_segment_tree{
    int tot,nd[N<<2];
    struct haha{
        int ls,rs,num;
    }tr[N<<9];
    void upd2(int &cnt,int l,int r,int L,int R,ll x){
        if(!cnt)cnt=++tot;
        if(l>=L&&r<=R){tr[cnt].num=merge(tr[cnt].num,x);return;}
        int mid=(l+r)>>1;
        if(mid>=L)upd2(tr[cnt].ls,l,mid,L,R,x);
        if(mid<R)upd2(tr[cnt].rs,mid+1,r,L,R,x);
    }
    void upd1(int cnt,int l,int r,int l1,int r1,int l2,int r2,ll x){
        if(l>=l1&&r<=r1){upd2(nd[cnt],1,n,l2,r2,x);return;}
        int mid=(l+r)>>1;
        if(mid>=l1)upd1(cnt<<1,l,mid,l1,r1,l2,r2,x);
        if(mid<r1)upd1(cnt<<1|1,mid+1,r,l1,r1,l2,r2,x);
    }
    void upd(int l1,int r1,int l2,int r2,ll x){
        if(l1>r1||l2>r2)return;
        upd1(1,1,n,l1,r1,l2,r2,x);
    }
    int query2(int cnt,int l,int r,int x){
        if(!cnt)return 0;
        if(l==r)return tr[cnt].num;
        int mid=(l+r)>>1;
        if(mid>=x)return merge(tr[cnt].num,query2(tr[cnt].ls,l,mid,x));
        else return merge(tr[cnt].num,query2(tr[cnt].rs,mid+1,r,x));
    }
    int query1(int cnt,int l,int r,int x,int y){
        if(l==r)return query2(nd[cnt],1,n,y);
        int mid=(l+r)>>1;
        if(mid>=x)return merge(query2(nd[cnt],1,n,y),query1(cnt<<1,l,mid,x,y));
        else return merge(query2(nd[cnt],1,n,y),query1(cnt<<1|1,mid+1,r,x,y));
    }     
}T;
struct normal_segment_tree{
    int tr[N<<2];
    void upd1(int cnt,int l,int r,int L,int R,ll x){
        if(l>=L&&r<=R){tr[cnt]=merge(tr[cnt],x);return;}
        int mid=(l+r)>>1;
        if(mid>=L)upd1(cnt<<1,l,mid,L,R,x);
        if(mid<R)upd1(cnt<<1|1,mid+1,r,L,R,x);
    }
    void upd(int l,int r,ll x){
        if(l>r)return;
        upd1(1,1,n,l,r,x); 
    }
    int query(int cnt,int l,int r,int x){
        if(l==r)return tr[cnt];
        int mid=(l+r)>>1;
        if(mid>=x)return merge(tr[cnt],query(cnt<<1,l,mid,x));
        else return merge(tr[cnt],query(cnt<<1|1,mid+1,r,x));
    }
}tree; 
int main(){
    n=rd();m=rd();int l,r,opt;
    for(int i=1;i<=m;++i){
        opt=rd();l=rd();r=rd();
        if(opt==1){
            ll nl=ni(r-l+1);
            T.upd(1,l-1,l,r,nl);
            T.upd(l,r,r+1,n,nl);
            T.upd(l,r,l,r,2ll*nl%mod);
            tree.upd(1,l-1,1);tree.upd(r+1,n,1);
            tree.upd(l,r,1ll*nl*(r-l)%mod); 
        }
        else{
            if(l==1)printf("%d\n",merge(1,tree.query(1,1,n,r)));
            else printf("%d\n",merge(1,T.query1(1,1,n,l-1,r)));
        }
    }
    return 0;
} 
posted @ 2019-02-28 14:42  comld  阅读(253)  评论(0编辑  收藏  举报