「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\n",(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\n",((!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;
}

原文地址:https://www.cnblogs.com/klauralee/p/10856017.html

时间: 2024-08-29 03:00:16

「ZJOI2017」树状数组的相关文章

bzoj4785【Zjoi2017】树状数组

漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的 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 的她写了如

【ZJOI2017】树状数组

sts维护两个数不同的概率就可以了 #include<cstdio> #include<iostream> #include<algorithm> const int mod = 998244353; typedef long long ll; inline int pow(int x,int y,int ans=1){ for(;y;y>>=1,x=ll(x)*x%mod) if(y&1)ans=ll(ans)*x%mod; return ans;

loj #535. 「LibreOJ Round #6」花火 树状数组求逆序对+主席树二维数点+整体二分

$ \color{#0066ff}{ 题目描述 }$ 「Hanabi, hanabi--」 一听说祭典上没有烟火,Karen 一脸沮丧. 「有的哦-- 虽然比不上大型烟花就是了.」 还好 Shinobu 早有准备,Alice.Ayaya.Karen.Shinobu.Yoko 五人又能继续愉快地玩耍啦! 「噢--!不是有放上天的烟花嘛!」Karen 兴奋地喊道. 「啊等等--」Yoko 惊呼.Karen 手持点燃引信的烟花,「嗯??」 Yoko 最希望见到的是排列优美的烟火,当然不会放过这个机会-

「CodePlus 2017 12 月赛」火锅盛宴(模拟+树状数组)

1A,拿来练手的好题 用一个优先队列按煮熟时间从小到大排序,被煮熟了就弹出来. 用n个vector维护每种食物的煮熟时间,显然是有序的. 用树状数组维护每种煮熟食物的数量. 每次操作前把优先队列里煮熟时间<=当前时间的弹出,BIT上+1. 每次0操作把食物塞进优先队列和vector 每次1操作先看看树状数组里有没有数,没有输出angry,有的话在树状数组上二分找到最小的数. 每次2操作先看看树状数组里有没有这一种数,有的话输出并-1,没有的话看看vector有没有,有的话输出时间差,没有的话输出

「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)

学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2*s_l-l$的区间$[l+1,r]$其众数为$x$,这个显然可以用一个数据结构来维护. 直接扫一遍效率是$O($数字种类数$*nlogn)$的,无法承受,但是我们发现,对于每一段非$x$的数,$2*s_i-i$是公差为$-1$的等差数列,所以它们对答案的贡献实际上可以一次性计算.设$L$为一段非$x$数

「树状数组」[SDOI2009]HH的项链

[SDOI2009]HH的项链 原题链接 [SDOI2009]HH的项链 题目大意 给你 \(n\) 个数,再给你 \(q\) 次询问,每次询问给你 \(l, r\) ,问你 \(l, r\) 中有多少个不同的数 题目题解 分析这道题我们发现,对于一个 \([L_1, R_1]\) 存在另一个 \([L_2, R_1]\) 且 \(L_2\) 严格大于 \(L_1\),那么就一定存在第一个区间不同的数 大于等于 第二个区间的不同的数,这里很显然有一种等于的情况,什么情况等于?在\([L_2,R_

csp-s模拟测试56(10.2)Merchant「二分」&#183;Equation「树状数组」

又死了......T1 Merchant 因为每个集合都可以写成一次函数的形式,所以假设是单调升的函数,那么随着t越大就越佳 而单调减的函数,随着t的增大结果越小,所以不是单调的??? 但是我们的单调只需凭借t时刻的sum值是否大于S即可 如果某个单减的集合符合情况,那么他在t==0时就符合情况 如果不符合,那么他就不会作出贡献 所以可以二分 T2 Equation 一开始以为是高斯消元??? 当然不是..... 把每个xi均用x1表示,那么我们发现,对于深度奇偶不同的点,他的表示方式是不同的,

【BZOJ4785】[Zjoi2017]树状数组 树套树(二维线段树)

[BZOJ4785][Zjoi2017]树状数组 Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1) mod 2. 2 l r,表示询问 sigma(Ai) mod 2,L<=i<=r 尽管那个时候的可怜非常的 simple,但是她还是发现这题可以用树状数组做.当时非常yo

[BZOJ4785][ZJOI2017]树状数组(概率+二维线段树)

4785: [Zjoi2017]树状数组 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 297  Solved: 195[Submit][Status][Discuss] Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道 基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1)