bzoj4785Zjoi2017树状数组

Posted paul-guderian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4785Zjoi2017树状数组相关的知识,希望对你有一定的参考价值。

漆黑的晚上,九条可怜躺在床上辗转反侧。难以入眠的她想起了若干年前她的一次悲惨的 OI 比赛经历。那是一道基础的树状数组题。

给出一个长度为 nn 的数组 AA,初始值都为 00,接下来进行 mm 次操作,操作有两种:

  • 1 x1 x, 表示将 AxAx 变成 (Ax+1)mod2(Ax+1)mod2。
  • 2 l r2 l r, 表示询问 (ri=lAi)mod2(∑i=lrAi)mod2。

尽管那个时候的可怜非常的 simple,但是她还是发现这题可以用树状数组做。当时非常 young 的她写了如下的算法:

技术分享图片


 

其中 lowbit(x)lowbit(x) 表示数字 x最低的非 00 二进制位,例如 lowbit(5)=1,lowbit(12)=4lowbit(5)=1,lowbit(12)=4。进行第一类操作的时候就调用 Add(x)Add(x),第二类操作的时候答案就是 Query(l,r)Query(l,r)。

如果你对树状数组比较熟悉,不难发现可怜把树状数组写错了:AddAdd 和 FindFind 中 xx 变化的方向反了。因此这个程序在最终测试时华丽的爆 00 了。

然而奇怪的是,在当时,这个程序通过了出题人给出的大样例——这也是可怜没有进行对拍的原因。

现在,可怜想要算一下,这个程序回答对每一个询问的概率是多少,这样她就可以再次的感受到自己是一个多么非的人了。然而时间已经过去了很多年,即使是可怜也没有办法完全回忆起当时的大样例。幸运的是,她回忆起了大部分内容,唯一遗忘的是每一次第一类操作的 xx 的值,因此她假定这次操作的 xx 是在 [li,ri][li,ri] 范围内等概率随机的。

具体来说,可怜给出了一个长度为 nn 的数组 AA,初始为 00,接下来进行了 mm 次操作:

  • 1 l r1 l r, 表示在区间 [l,r][l,r] 中等概率选取一个 xx 并执行 Add(x)Add(x)。
  • 2 l r2 l r, 表示询问执行 Query(l,r)Query(l,r) 得到的结果是正确的概率是多少。

输入格式

第一行输入两个整数 n,mn,m。 接下来 mm 行每行描述一个操作,格式如题目中所示。


 

输出格式

对于每组询问,输出一个整数表示答案。如果答案化为最简分数后形如 xyxy,那么你只需要输出 x×y1mod998244353x×y−1mod998244353 后的值。(即输出答案模 998244353998244353)。


 

  • 题解

    • 把询问看成修改,修改看成询问,可以发现这样子的树状数组在$l==0$时得到$0$,$l!=0$时得到l的后缀和   
    • 所以问题变成了区间等概率修改+:
    • $l==1$,询问$r$的前缀和和后缀和相同的概率;
    • $l!=1$,询问$l-1$和$r$相同的概率;
    • (由于不太了解线性独立这个概念,所以试了一些很奇怪的方法例如维护相邻概率合并之类的。。。。。)
    • 考虑$[l,r]$中$l-1!=0$,等于零类似;
    • $p[x,y]$表示$x$和$y$相同的概率,由于是异或操作,只有相等和不等两种情况;
    • 对一个区间修改分一个和两个点都在区间讨论可以知道被修改的概率$q$;
    • $p = p*(1-q) + (1-p)*q$
    • 和更新顺序无关并且可以合并;
    • 二维线段树维护概率;
  • 技术分享图片
     1 #include<bits/stdc++.h>
     2 #define rg register
     3 #define ll long long 
     4 using namespace std;
     5 const int N=100010,mod=998244353;
     6 int n,m,sz1,sz2,Ls[N*400],Rs[N*400],lz[N*400],rt[N<<2],ls[N<<2],rs[N<<2],Rt,ans;
     7 int inv(ll x){
     8     ll re=1;
     9     for(int y=mod-2;y;y>>=1,x=x*x%mod){
    10         if(y&1)re=re*x%mod;
    11     }
    12     return re;
    13 }
    14 char gc(){
    15     static char*p1,*p2,s[1000000];
    16     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
    17     return(p1==p2)?EOF:*p1++;
    18 }
    19 int rd(){
    20     int x=0; char c=gc();
    21     while(c<0||c>9)c=gc();
    22     while(c>=0&&c<=9)x=x*10+c-0,c=gc();
    23     return x; 
    24 }
    25 void update(int&k,int l,int r,int x,int y,int p){
    26     if(!k)lz[k=++sz2]=1;
    27     if(l==x&&r==y){
    28         lz[k]=((ll)lz[k]*(mod+1-p)+(ll)(mod+1-lz[k])*p)%mod;    
    29         return ;
    30     }
    31     else{
    32         int mid=(l+r)>>1;
    33         if(y<=mid)update(Ls[k],l,mid,x,y,p);
    34         else if(x>mid)update(Rs[k],mid+1,r,x,y,p);
    35         else update(Ls[k],l,mid,x,mid,p),update(Rs[k],mid+1,r,mid+1,y,p);
    36     }
    37 }
    38 void query(int k,int l,int r,int x){
    39     if(!k)return;
    40     ans = ((ll)ans*lz[k] + (ll)(mod+1-ans)*(mod+1-lz[k]))%mod;
    41     if(l==r)return;
    42     else{
    43         int mid=(l+r)>>1;
    44         if(x<=mid)query(Ls[k],l,mid,x);
    45         else query(Rs[k],mid+1,r,x);
    46     }
    47 } 
    48 void Update(int&k,int l,int r,int x1,int x2,int y1,int y2,int p){
    49     if(!k)k=++sz1;
    50     if(l==x1&&r==x2)update(rt[k],1,n,y1,y2,p); 
    51     else{
    52         int mid=(l+r)>>1;
    53         if(x2<=mid)Update(ls[k],l,mid,x1,x2,y1,y2,p);
    54         else if(x1>mid)Update(rs[k],mid+1,r,x1,x2,y1,y2,p);
    55         else Update(ls[k],l,mid,x1,mid,y1,y2,p),Update(rs[k],mid+1,r,mid+1,x2,y1,y2,p);
    56     }
    57 }
    58 void Query(int k,int l,int r,int x,int y){
    59     if(!k)return;
    60     query(rt[k],1,n,y);
    61     if(l==r)return;
    62     else{
    63         int mid=(l+r)>>1;
    64         if(x<=mid)Query(ls[k],l,mid,x,y);
    65         else Query(rs[k],mid+1,r,x,y);
    66     }
    67 }
    68 int cnt,a[N];
    69 inline void print(int x){
    70     if(!x){putchar(48);putchar(10);return;}
    71     cnt=0;
    72     while(x)a[++cnt]=x%10,x/=10;
    73     for(rg int i=cnt;i;--i)putchar(a[i]+48);
    74     putchar(10);
    75 }
    76 int main(){
    77     #ifndef ONLINE_JUDGE
    78     freopen("T2.in","r",stdin);
    79     freopen("T2.out","w",stdout);
    80     #endif
    81     n=rd();m=rd();
    82     for(rg int i=1,l,r,op;i<=m;++i){
    83         op=rd();l=rd();r=rd();
    84         if(op==1){
    85             int p = inv(r-l+1);
    86             if(l>1)Update(Rt,1,n,1,l-1,l,r,p),update(rt[0],1,n,1,l-1,1);
    87             if(r<n)Update(Rt,1,n,l,r,r+1,n,p),update(rt[0],1,n,r+1,n,1);
    88             if(l<r)Update(Rt,1,n,l,r,l,r,p*2%mod),update(rt[0],1,n,l,r,(mod+1-p)%mod);
    89         }else{
    90             ans=1;
    91             if(l==1)query(rt[0],1,n,r);
    92             else Query(Rt,1,n,l-1,r);
    93             print(ans);
    94         //    printf("%d
    ",ans);
    95         }
    96     }
    97 //    printf("%.2lf
    ",1.0*clock()/CLOCKS_PER_SEC);
    98     return 0;
    99 }
    bzoj4785

     

以上是关于bzoj4785Zjoi2017树状数组的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4785Zjoi2017树状数组

BZOJ4785 [Zjoi2017]树状数组 二维线段树 + 标记永久化

BZOJ 4785 [Zjoi2017]树状数组 | 二维线段树

bzoj4785[Zjoi2017]树状数组 线段树套线段树

BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

BZOJ_3110_[Zjoi2013]K大数查询_整体二分+树状数组