- 给定一个长度为(n)的数组,有两种操作:
- 随机给区间([l,r])中某一位置的值加上(1)。
- 询问区间([l,r])所有位置的和模(2)的余数。
- 对于每个询问,求如果把树状数组写反了,与正确的答案相同的概率。
- (nle10^5)
感觉这道题应该不是很难吧,至少我都能自己做出来。
不过这可能也是得益于不小心看到了二维线段树这一标签。。。
题意转化
注意这里的询问是以(2)为模数的,而(xequiv -x(mod 2))。
发现树状数组写反了,就意味着现在得到的是区间([l-1,r-1])所有位置的和。
那么也就是求(a_{l-1})和(a_r)相同的概率。
二维线段树
考虑我们用((i,j))表示(i)和(j)两个位置值相同的概率。
对于一次修改([l,r]),令(t=frac{1}{r-l+1}),然后发现对于((i,j))有以下几种变化的可能:
- (i,j)都不在([l,r])范围内,无影响。
- (i,j)都在([l,r])范围内,有(2t)的概率选中其中一个数导致值改变,(1-2t)的概率没选中。
- (i,j)有且仅有一个在([l,r])范围内,有(t)的概率选择区间中那个数导致值改变,(1-t)的概率没选中。
考虑如何合并两个值不变的概率(x,y),容易发现就是(x imes y+(1-x) imes(1-y))。(即要么都不变,要么都变)
那么就可以直接拿二维线段树维护了。
具体实现时为了好写,可以考虑标记永久化。
(l=1)的特殊情况
注意,其实我们还要特殊处理(l=1),即(l-1=0)的情况。
此时得到的应该是([r,n])所有位置的和,而本应得到的是([1,r])所有位置的和,也就是要求出除第(r)个位置以外所有数之和为(0)的概率。
可以发现一个位置与(0)的答案值不变的概率就是它作为被修改位置的概率。
这其实和一般情况还是基本一致的,只要单独对这种情况开一个(0)号节点就好了,省得重写一个线段树。
代码:(O(nlog^2n))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define LN 20
#define X 998244353
using namespace std;
int n;I int G(CI x,CI y) {return (1LL*x*y+1LL*(1-x+X)*(1-y+X))%X;}//合并两个值不变的概率
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
class SegSegTree//标记永久化二维线段树
{
private:
#define PT CI l=0,CI r=n
#define LT l,mid
#define RT mid+1,r
int Rt[N<<2];class SegmentTree
{
private:
int Nt;struct node{int V,S[2];}O[N*LN*LN+5];
public:
I void U(int& rt,CI L,CI R,CI v,PT)//区间修改
{
if(!rt&&(O[rt=++Nt].V=1),L<=l&&r<=R) return (void)(O[rt].V=G(O[rt].V,v));
RI mid=l+r>>1;L<=mid&&(U(O[rt].S[0],L,R,v,LT),0),R>mid&&(U(O[rt].S[1],L,R,v,RT),0);
}
I int Q(CI rt,CI y,PT)//单点询问
{
if(!rt) return 1;if(l==r) return O[rt].V;RI mid=l+r>>1;
return G(y<=mid?Q(O[rt].S[0],y,LT):Q(O[rt].S[1],y,RT),O[rt].V);
}
}S;
public:
I void U(CI L,CI R,CI _l,CI _r,CI v,PT,CI rt=1)//区间修改
{
if(L<=l&&r<=R) return S.U(Rt[rt],_l,_r,v);RI mid=l+r>>1;
L<=mid&&(U(L,R,_l,_r,v,LT,rt<<1),0),R>mid&&(U(L,R,_l,_r,v,RT,rt<<1|1),0);
}
I int Q(CI x,CI y,PT,CI rt=1)//单点询问
{
if(l==r) return S.Q(Rt[rt],y);RI mid=l+r>>1;
return G(x<=mid?Q(x,y,LT,rt<<1):Q(x,y,RT,rt<<1|1),S.Q(Rt[rt],y));
}
}T;
int main()
{
RI Qt,op,x,y,t;scanf("%d%d",&n,&Qt);W(Qt--) switch(scanf("%d%d%d",&op,&x,&y),op)
{
case 1:t=QP(y-x+1,X-2),T.U(x,y,x,y,(1-2LL*t%X+X)%X),T.U(0,0,x,y,t),//两个都在区间中
x^1&&(T.U(1,x-1,x,y,(1-t+X)%X),T.U(0,0,1,x-1,0),0),//有且仅有一个
y^n&&(T.U(x,y,y+1,n,(1-t+X)%X),T.U(0,0,y+1,n,0),0);break;//有且仅有一个
case 2:printf("%d
",T.Q(x-1,y));break;//查询x-1和y值相同的概率
}return 0;
}