zoukankan      html  css  js  c++  java
  • 「ZJOI2017」树状数组

    「ZJOI2017」树状数组

    以下均基于模2意义下,默认(n,m)同阶。

    熟悉树状数组的应该可以发现,这题其实是求(l-1)(r)位置值相同的概率。

    显然(l=1)的情况需要特盘。

    大暴力

    对于(l=1)的情况,可以发现一个操作不会产生影响当且仅当增加(r)的值,而其他情况会改变(l-1)(r)

    对于(l!=1)的情况:

    ​ 针对一次修改区间([ql,qr])

    1. ([ql,qr])包含(l-1,r),那么有(displaystyle 2 over qr-ql+1)概率使(l-1)(r)的值改变。
    2. ([ql,qr])不包含(l-1,r),不会发生变化。
    3. ([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])的点,对于暴力的第3类,即(x in [1,ql -1],y in [ql,qr]),(x in [ql,qr],y in [qr+1,n])

    只需二维线段树区间标记即可,为了方便,标记表示的是 对应的二维区间的点 发生变化的概率。

    #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
    ",(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
    ",((!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;
    }
    
  • 相关阅读:
    贰、js的基础(二)类型转换
    贰、js的基础(一)
    ajax的异步请求小结
    壹、js的概述
    sass的用法小结(四)进阶篇
    sass的用法小结(三)
    sass的用法小结(二)
    sass的用法小结(一)
    H5页面在线制作工具搜集
    H5教程:移动页面性能优化
  • 原文地址:https://www.cnblogs.com/klauralee/p/10856017.html
Copyright © 2011-2022 走看看