「ZJOI2017」樹狀數組
阿新 • • 發佈:2019-05-13
isp define %d 需要 type size 一個 dimens get 的點,對於暴力的第3類,即\(x \in [1,ql -1],y \in [ql,qr]\),\(x \in [ql,qr],y \in [qr+1,n]\)。
「ZJOI2017」樹狀數組
以下均基於模2意義下,默認\(n,m\)同階。
熟悉樹狀數組的應該可以發現,這題其實是求\(l-1\)和\(r\)位置值相同的概率。
顯然\(l=1\)的情況需要特盤。
大暴力
對於\(l=1\)的情況,可以發現一個操作不會產生影響當且僅當增加\(r\)的值,而其他情況會改變\(l-1\)或\(r\)。
對於\(l!=1\)的情況:
? 針對一次修改區間\([ql,qr]\)。
- \([ql,qr]\)包含\(l-1,r\),那麽有\(\displaystyle 2 \over qr-ql+1\)概率使\(l-1\)或\(r\)的值改變。
- \([ql,qr]\)不包含\(l-1,r\)
- \([ql,qr]\)包含\(l-1,r\)中一個,那麽有\(\displaystyle 1 \over qr-ql+1\)使\(l-1\)或\(r\)的值改變。
把每次修改記下來,就可以寫出\(o(n^2)\)的暴力了。
代碼見namespace fc?
正解
顯然可以只記相等的概率。
可以發現,對於一次詢問,改變前面修改的順序並不會改變該詢問的答案。
也就是說它滿足交換律。
對於\(l=1\)的情況,顯然可以一棵線段樹維護。
對於\(l!=1\)的情況,把\([l,r ]\)區間當做一個二維的點\((l,r)\),那麽每一次修改都會對二維區間產生貢獻。
具體的:對於暴力分的第1類,即\(x \in [ql,qr],y \in [ql,qr]\)
只需二維線段樹區間標記即可,為了方便,標記表示的是 對應的二維區間的點 發生變化的概率。
#include<bits/stdc++.h> #define rep(q,a,b) for(int q=a,q##_end_=b;q<=q##_end_;++q) #define dep(q,a,b) for(int q=a,q##_end_=b;q>=q##_end_;--q) #define mem(a,b) memset(a,b,sizeof a ) #define debug(a) cerr<<#a<<' '<<a<<"___"<<endl using namespace std; template<typename T> void in(T &r) { static char c; r=0; while(c=getchar(),!isdigit(c)); do r=(r<<1)+(r<<3)+(c^48); while(c=getchar(),isdigit(c)); } bool cur1; int n,m; const int mn=100005; const int mod=998244353; int inv[mn]; namespace fc{ int l[3005],r[3005]; void solve(){ int ty,a,b; int ct=0; while(m--){ in(ty),in(a),in(b); if(ty==1)++ct,l[ct]=a,r[ct]=b; else{ --a; int wi=1,wo=0; if(!a){ rep(q,1,ct){ int len=r[q]-l[q]+1; if(l[q]<=b&&b<=r[q]){ int mid1=wi,mid2=wo; wi=(1LL*mid2*(1-inv[len])+1LL*mid1*inv[len])%mod; wo=(1LL*mid1*(1-inv[len])+1LL*mid2*inv[len])%mod; }else swap(wi,wo); } }else{ rep(q,1,ct){ int len=r[q]-l[q]+1; int mid1=wi,mid2=wo; if(l[q]<=a&&b<=r[q]){//[l[q],r[q]]->[l[q],r[q]] wi=(1LL*mid1*(1-2*inv[len])+1LL*mid2*2*inv[len])%mod; wo=(1LL*mid2*(1-2*inv[len])+1LL*mid1*2*inv[len])%mod; }else if(l[q]<=b&&b<=r[q]||l[q]<=a&&a<=r[q]){ //[1,l[q]-1]->[l[q],r[q]] //[l[q],r[q]]->[r[q]+1,n] wi=(1LL*mid1*(1-inv[len])+1LL*mid2*inv[len])%mod; wo=(1LL*mid2*(1-inv[len])+1LL*mid1*inv[len])%mod; } } } printf("%d\n",(wi+mod)%mod); } } } } namespace something_just_for_fun{ struct two_dimensional_segment_tree{ int tot,lson[mn*400],rson[mn*400],addv[mn*400],rt[mn<<2]; two_dimensional_segment_tree(){ tot=0; } int y_1,y_2,y_3,y_4,ad_v; void se_add(int &o,int l,int r){ if(!o)o=++tot; if(y_3<=l&&r<=y_4){ addv[o]=(1LL*(1-addv[o])*ad_v+1LL*addv[o]*(1-ad_v))%mod; }else{ int mid=l+r>>1; if(y_3<=mid)se_add(lson[o],l,mid); if(y_4>mid)se_add(rson[o],mid+1,r); } } void fi_add(int o,int l,int r){ if(y_1<=l&&r<=y_2)se_add(rt[o],1,n); else{ int mid=l+r>>1; if(y_1<=mid)fi_add(o<<1,l,mid); if(y_2>mid)fi_add(o<<1|1,mid+1,r); } } void add(int l,int r,int l1,int r1,int v){ if(l>r||l1>r1)return; y_1=l,y_2=r,y_3=l1,y_4=r1,ad_v=v; fi_add(1,1,n); } int v; void se_ask(int &o,int l,int r){ if(!o)return; v=(1LL*(1-addv[o])*v+1LL*addv[o]*(1-v))%mod; int mid=l+r>>1; if(y_2<=mid)se_ask(lson[o],l,mid); else se_ask(rson[o],mid+1,r); } void fi_ask(int o,int l,int r){ se_ask(rt[o],1,n); if(l==r)return; else{ int mid=l+r>>1; if(y_1<=mid)fi_ask(o<<1,l,mid); else fi_ask(o<<1|1,mid+1,r); } } int ask(int l,int r){ y_1=l,y_2=r,v=1; fi_ask(1,1,n); return v; } }an; struct segment_tree{ int addv[mn<<2]; int y_1,y_2,ad_v; void fi_add(int o,int l,int r){ if(y_1<=l&&r<=y_2)addv[o]=(1LL*(1-addv[o])*ad_v+1LL*addv[o]*(1-ad_v))%mod; else{ int mid=l+r>>1; if(y_1<=mid)fi_add(o<<1,l,mid); if(y_2>mid)fi_add(o<<1|1,mid+1,r); } } void add(int l,int r,int v){ if(l>r)return; y_1=l,y_2=r,ad_v=v; fi_add(1,1,n); } int v; void fi_ask(int o,int l,int r){ v=(1LL*(1-addv[o])*v+1LL*addv[o]*(1-v))%mod; if(l==r)return; else{ int mid=l+r>>1; if(y_1<=mid)fi_ask(o<<1,l,mid); else fi_ask(o<<1|1,mid+1,r); } } int ask(int x){ y_1=x,v=1; fi_ask(1,1,n); return v; } }at; int l[mn],r[mn]; void solve(){ int ty,a,b; while(m--){ in(ty),in(a),in(b); if(ty==1){ at.add(a,b,1-inv[b-a+1]),at.add(1,a-1,1),at.add(b+1,n,1); an.add(a,b,a,b,2*inv[b-a+1]%mod),an.add(1,a-1,a,b,inv[b-a+1]),an.add(a,b,b+1,n,inv[b-a+1]); } else --a,printf("%d\n",((!a?at.ask(b):an.ask(a,b))+mod)%mod); } } } bool cur2; int main(){ // cerr<<(&cur2-&cur1)/1024.0/1024<<endl; freopen("bit.in","r",stdin); freopen("bit.out","w",stdout); in(n),in(m); inv[0]=inv[1]=1; rep(q,2,n)inv[q]=1LL*(mod-mod/q)*inv[mod%q]%mod; something_just_for_fun::solve(); return 0; }
「ZJOI2017」樹狀數組