zoukankan      html  css  js  c++  java
  • BZOJ4785 [Zjoi2017]树状数组

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

    题目链接:BZOJ4785

    正解:二维线段树

    解题报告:

      考场上我一眼看出了这个变成了后缀和,然而被$l=1$坑成了暴力分==  好坑啊…

      考虑变成后缀和之后,我们只需要$check$一下$l-1$和$r$的被修改次数是否相同,这个概率如果我们能维护的话每次直接查询就好了。

      我们把$(x,y)$看成一个二维数点,表示$x$与$y$修改次数相同的概率,那么不相同的概率也能直接算了。

      为了方便,我们只记录$x<y$的情况就好了。这个东西我们显然可以用二维线段树来维护。

      考虑每次查询直接查询$(l-1,r)$就好了。

      对于修改呢,对于$[1,l-1]$、$[l+1,r]$这两个区间都会对$[l,r]$中的数有$1-p$的概率不改变相同性,$p=1/区间长度$,即选中区间一个数的概率。

      而考虑区间内部的情况呢,就是$1-p*2$。

      这个东西直接在二维线段树上维护就好了,这个标记可以直接合并,因为两个概率可以用$p1*p2+(1-p1)*(1-p2)$的式子合并。

      注意卡卡空间,卡卡常数==

    //It is made by ljh2000
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cstdio>
    #include <string>
    #include <queue>
    #include <cmath>
    #include <ctime>
    #define lc root<<1
    #define rc root<<1|1
    #define rep(i,j,k) for(int i=j;i<=k;i++)
    #define reg(i,x) for(int i=first[x];i;i=next[i])
    using namespace std;
    typedef long long LL;
    const int MAXN = 200011;
    const int mod = 998244353;
    int n,m,cnt,RT[MAXN*3];
    int ans,P[MAXN*180];
    struct node{ int ls,rs; }a[MAXN*180];//维护二元组修改次数相等的概率
    inline int fast_pow(int x,int y){ int r=1; while(y>0) { if(y&1) r=1LL*r*x%mod; x=1LL*x*x%mod; y>>=1; } return r; }
    inline int merge(int x,int y){ return ( 1LL*x*y%mod+1LL*(1-x+mod)*(1-y+mod)%mod )%mod; }
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void build(int root,int l,int r){
    	cnt=max(cnt,root); if(l==r) return ;
    	int mid=(l+r)>>1; build(lc,l,mid); build(rc,mid+1,r);
    }
    
    inline void modify(int &root,int l,int r,int ql,int qr,int CC){
    	if(!root) root=++cnt,P[root]=1;//!!!默认修改次数相等
    	if(ql<=l && r<=qr) { P[root]=merge(P[root],CC); return ; }
    	int mid=(l+r)>>1; 
    	if(ql<=mid) modify(a[root].ls,l,mid,ql,qr,CC);
    	if(qr>mid) modify(a[root].rs,mid+1,r,ql,qr,CC);
    }
    
    inline void Modify(int root,int l,int r,int ql,int qr,int down,int up,int CC){
    	if(ql<=l && r<=qr) { modify(RT[root],0,n+1,down,up,CC); return ; }
    	int mid=(l+r)>>1;
    	if(ql<=mid) Modify(lc,l,mid,ql,qr,down,up,CC);
    	if(qr>mid) Modify(rc,mid+1,r,ql,qr,down,up,CC);
    }
    
    inline void query(int &root,int l,int r,int pos){
    	if(!root) return ; ans=merge(ans,P[root]);//!!!
    	if(l==r) return ; int mid=(l+r)>>1;
    	if(pos<=mid) query(a[root].ls,l,mid,pos);
    	else query(a[root].rs,mid+1,r,pos);
    }
    
    inline void Query(int root,int l,int r,int posx,int posy){
    	if(RT[root]) query(RT[root],0,n+1,posy);//!!!
    	if(l==r) return ; int mid=(l+r)>>1;
    	if(posx<=mid) Query(lc,l,mid,posx,posy);
    	else Query(rc,mid+1,r,posx,posy);
    }
    
    inline void work(){
    	n=getint(); m=getint(); int type,l,r,p;
    	build(1,0,n);
    	for(int i=1;i<=m;i++) {
    		type=getint(); l=getint(); r=getint();
    		if(type==1) {
    			p=fast_pow(r-l+1,mod-2);
    
    			//[l,r]->[1,l-1] 1-p
    			if(l>1) {
    				Modify(1,1,n,1,l-1,l,r,(1-p+mod)%mod);
    				modify(RT[0],1,n,1,l-1,0);
    			}
    			//[l,r]->[r+1,n] 1-p
    			if(r<n) {
    				Modify(1,1,n,l,r,r+1,n,(1-p+mod)%mod);
    				modify(RT[0],1,n,r+1,n,0);//!!!n+1,后缀和!!!
    			}
    
    			//[l,r]->[l,r] 1-p*2
    			if(l!=r) Modify(1,1,n,l,r,l,r,(1-p*2+mod+mod)%mod);
    
    			//l=1说明查询前缀和和后缀和是否相等
    			//那么修改序列中每个数的前缀和与后缀和相等概率
    			modify(RT[0],1,n,l,r,p);//只有修改到自己才不会改变前缀和与后缀和的相等性
    		}
    		else {
    			ans=1;
    			if(l==1) query(RT[0],1,n,r);
    			else Query(1,1,n,l-1,r);
    			printf("%d
    ",ans);
    		}
    	}
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("bit.in","r",stdin);
    	freopen("bit.out","w",stdout);
    #endif
        work();
        return 0;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    java判断一个字符串是否包含某个字符
    Java去掉Html标签的方法
    如何转换成utf-8格式的,在jsp页面中正常显示换行
    a标签设置手型
    a标签置灰不可点击
    校验手机号码格式
    用JQuery 判断某个属性是否存在hasAttr的解决方法
    验证手机号码 (包含166和199)
    获取短信验证码倒计时
    Noisy Channel模型纠正单词拼写错误
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6686960.html
Copyright © 2011-2022 走看看