zoukankan      html  css  js  c++  java
  • ●洛谷P3688 [ZJOI2017]树状数组

    题链:

    https://www.luogu.org/problemnew/show/P3688
    题解:

    二维线段树。

    先不看询问时l=1的特殊情况。


    对于一个询问(l,r),如果要让错误的程序得到正确答案,
    显然应该满足l-1位置的值=r位置的值(或者说两个位置的异或值为0)。
    那么定义二元组函数f(x,y)表示x位置与y位置的异或值为0的概率
    如果可以维护出所有这样的二元组的函数值,
    对于一个询问的话,就可以很方便的回答了。
    现在看看,怎样维护这样的二元组的函数值。
    假设现在给出了一个操作1:(L,R),(令prob=1/len)
    那么显然,对于如下这些二元组:(0~L-1,L~R)和(L~R,R+1~N),
    它们的函数值都会乘上(1-prob),因为有(1-prob)的概率无法使得其异或值改变。
    再对于这些二元组(L~R,L~R),它们的函数值都会乘上(1-2*prob)。
    把上面的二元组看出平面上的点,那么每个操作1就对应着改变平面上若干个矩形的值。
    所以就直接使用二维线段树(树套树)去维护二维区间修改+单点查询

    至于询问中l=1的情况,如果要让错误程序得到正确答案,那么[1~r-1]这一段的异或和就应该等于[r+1~N]这一段的异或和。
    这里有这么一种做法:
    记录到当前询问位置,之前有了cnt个1操作。
    然后二维线段树查询f(0,r)的得到prob,
    由于0位置不可能被随机到1操作,
    所以prob就表示r位置被之前的所有1操作弄成0的概率,(即有偶数个1操作随机到了r位置的概率)。
    如果cnt为偶数,那么一定[1~r-1]这一段和[r+1~N]这一段被1操作随机到的奇偶性相同,
    也就是说[1~r-1]这一段的异或和就应该等于[r+1~N]这一段的异或和,所以答案就是prob.

    反之,如果cnt为奇数,(1-prob)表示r位置被之前的所有1操作弄成1的概率,(即有奇数个1操作随机到了r位置的概率)。
    这样的话那么也一定[1~r-1]这一段和[r+1~N]这一段被1操作随机到的奇偶性相同,
    也就是说[1~r-1]这一段的异或和就应该等于[r+1~N]这一段的异或和,所以答案就是(1-prob).


    代码:

    #include<bits/stdc++.h>
    #define MAXN 100005
    using namespace std;
    const int MOD=998244353;
    int N,M,cnt;
    int merge(int p1,int p2){
    	return (1ll*p1*p2+1ll*(1-p1+MOD)*(1-p2+MOD))%MOD;
    }
    struct SGT2{
    	int size;
    	int ls[MAXN*200],rs[MAXN*200],p[MAXN*200];
    	void Modify(int &u,int l,int r,int yl,int yr,int prob){
    		if(!u) u=++size,p[u]=1;
    		if(yl<=l&&r<=yr) return (void)(p[u]=merge(p[u],prob));
    		int mid=(l+r)>>1;
    		if(yl<=mid) Modify(ls[u],l,mid,yl,yr,prob);
    		if(mid<yr) Modify(rs[u],mid+1,r,yl,yr,prob);
    	}
    	int Query(int u,int l,int r,int py){
    		if(!u) return 1;
    		int ret=merge(1,p[u]);
    		if(l==r) return ret;
    		int mid=(l+r)>>1;
    		if(py<=mid) ret=merge(ret,Query(ls[u],l,mid,py));
    		else ret=merge(ret,Query(rs[u],mid+1,r,py));
    		return ret;
    	}
    }DTy;
    struct SGT1{
    	int size,root;
    	int ls[MAXN*2],rs[MAXN*2],yroot[MAXN*2];
    	void Modify(int &u,int l,int r,int xl,int xr,int yl,int yr,int prob){
    		if(!u) u=++size;
    		if(xl<=l&&r<=xr) return DTy.Modify(yroot[u],0,N+1,yl,yr,prob);
    		int mid=(l+r)>>1;
    		if(xl<=mid) Modify(ls[u],l,mid,xl,xr,yl,yr,prob);
    		if(mid<xr) Modify(rs[u],mid+1,r,xl,xr,yl,yr,prob);
    	}
    	int Query(int u,int l,int r,int px,int py){
    		if(!u) return 1;
    		int ret=merge(1,DTy.Query(yroot[u],0,N+1,py));
    		if(l==r) return ret;
    		int mid=(l+r)>>1;
    		if(px<=mid) ret=merge(ret,Query(ls[u],l,mid,px,py));
    		else ret=merge(ret,Query(rs[u],mid+1,r,px,py));
    		return ret;
    	}
    }DTx;
    int fastpow(int a,int b){
    	int ret=1;
    	for(;b;a=1ll*a*a%MOD,b>>=1)
    		if(b&1) ret=1ll*ret*a%MOD;
    	return ret;
    }
    int main(){
    	//cout<<fastpow(3,MOD-2)<<endl;
    	scanf("%d%d",&N,&M);
    	int t,l,r,prob,ans;
    	for(int i=1;i<=M;i++){
    		scanf("%d%d%d",&t,&l,&r);
    		if(t==1){
    			cnt++;
    			prob=fastpow(r-l+1,MOD-2);
    			DTx.Modify(DTx.root,0,N+1,0,l-1,l,r,(1ll-prob+MOD)%MOD);
    			DTx.Modify(DTx.root,0,N+1,l,r,r+1,N+1,(1ll-prob+MOD)%MOD);
    			if(r-l+1>=2) DTx.Modify(DTx.root,0,N+1,l,r,l,r,(1ll-2ll*prob+2ll*MOD)%MOD);
    		}
    		else{
    			l--;
    			ans=DTx.Query(DTx.root,0,N+1,l,r);
    			if(l==0){
    				if((cnt&1)==0) printf("%d
    ",ans);
    				else printf("%d
    ",(1-ans+MOD)%MOD);
    			}
    			else printf("%d
    ",ans);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    6.11 考试修改+总结
    6.10 考试修改+总结+颓废记
    我们都一样
    【HDU 5730】Shell Necklace
    【SPOJ 8093】Sevenk Love Oimaster
    【BZOJ 3238】【AHOI 2013】差异
    【UOJ #131】【NOI 2015】品酒大会
    【SPOJ 220】Relevant Phrases of Annihilation
    【POJ 3177】Redundant Paths
    【POJ 2186】Popular Cows
  • 原文地址:https://www.cnblogs.com/zj75211/p/8541662.html
Copyright © 2011-2022 走看看