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