题目描述:这里有一个写挂的树状数组:

有两种共\(m\)个操作:

  1. 输入\(l,r\),在\([l,r]\)中随机选择一个整数\(x\)执行\(\text{Add}(x)\)

  2. 输入\(l,r\),询问执行\(\text{Query}(l,r)\)的答案正确的概率\(\text{mod} \ 998244353\)。

数据范围:\(n,m\leq 100000\)


首先,根据这个代码,我们知道这就是一个单点修改求后缀和的数据结构。所以\(\text{Query}(l,r)\)求的是\([l-1,r-1]\)的和。所以正确当且仅当\(a_{l-1}=a_r\)。

注意,如果你直接维护每个数为\(0,1\)的概率,就会出现可能多次修改的问题。所以要\((x,y)\)维护\(a_x\neq a_y\)的概率。我们知道\(a_x\neq a_y\)的概率为\(p\),并以\(q\)的概率修改,则之后的概率为\(p(1-q)+q(1-p)\),这个标记是可合并的。所以:

  1. 若\(x\in [1,l-1],y\in [l,r]\)或\(x\in [l,r],y\in [r+1,n]\),则以\(\frac{1}{r-l+1}\)的概率修改。
  2. 若\(x,y\in [l,r]\),则以\(\frac{2}{r-l+1}\)的概率修改。

注意,上面\(\text{Find}(x)\)特判了\(x=0\)的情况,所以若\(l=1\)则计算的是\(r\)的后缀和,所以用\((0,x)\)维护\(x\)的前缀和是否等于\(x\)的后缀和的概率。

  1. 若\(x\notin [l,r]\),则以1的概率修改。
  2. 若\(x\in [l,r]\),则以\(\frac{r-l}{r-l+1}\)的概率修改。

而且询问是单点询问,所以我们可以使用二维线段树维护并标记永久化。

如果你不想卡常并最大点使用时限\(-0.01s\)通过Luogu评测,而且不能在UOJ通过,可以使用cdq分治,但是我不会。。。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 100003, mod = 998244353;
inline int kasumi(int a, int b){
int res = 1;
while(b){
if(b & 1) res = (LL) res * a % mod;
a = (LL) a * a % mod; b >>= 1;
}
return res;
}
int n, m, inv[N], root[N << 2], val[N * 350], ls[N * 350], rs[N * 350], cnt;
inline int Add(int a, int b){return (a + b >= mod) ? (a + b - mod) : (a + b);}
inline int Sub(int a, int b){return (a < b) ? (a + mod - b) : (a - b);}
inline int add(int a, int b){return Add((LL) a * Sub(1, b) % mod, (LL) b * Sub(1, a) % mod);}
inline void change(int &x, int L, int R, int l, int r, int v){
if(!x) x = ++ cnt;
if(l <= L && R <= r){val[x] = add(val[x], v); return;}
int mid = L + R >> 1;
if(l <= mid) change(ls[x], L, mid, l, r, v);
if(mid < r) change(rs[x], mid + 1, R, l, r, v);
}
inline int query(int x, int L, int R, int p){
if(!x) return 0;
if(L == R) return val[x];
int mid = L + R >> 1;
if(p <= mid) return add(val[x], query(ls[x], L, mid, p));
else return add(val[x], query(rs[x], mid + 1, R, p));
}
inline void change(int x, int L, int R, int l1, int r1, int l2, int r2, int v){
if(l1 <= L && R <= r1){change(root[x], 1, n, l2, r2, v); return;}
int mid = L + R >> 1;
if(l1 <= mid) change(x << 1, L, mid, l1, r1, l2, r2, v);
if(mid < r1) change(x << 1 | 1, mid + 1, R, l1, r1, l2, r2, v);
}
inline int query(int x, int L, int R, int p1, int p2){
if(L == R) return query(root[x], 1, n, p2);
int mid = L + R >> 1;
if(p1 <= mid) return add(query(root[x], 1, n, p2), query(x << 1, L, mid, p1, p2));
else return add(query(root[x], 1, n, p2), query(x << 1 | 1, mid + 1, R, p1, p2));
}
int main(){
scanf("%d%d", &n, &m);
for(Rint i = 1;i <= n;i ++) inv[i] = kasumi(i, mod - 2);
while(m --){
int opt, l, r;
scanf("%d%d%d", &opt, &l, &r);
if(opt == 1){
if(l > 1){
change(root[0], 1, n, 1, l - 1, 1);
change(1, 1, n, 1, l - 1, l, r, inv[r - l + 1]);
}
if(r < n){
change(root[0], 1, n, r + 1, n, 1);
change(1, 1, n, l, r, r + 1, n, inv[r - l + 1]);
}
if(l < r) change(1, 1, n, l, r, l, r, 2ll * inv[r - l + 1] % mod);
change(root[0], 1, n, l, r, Sub(1, inv[r - l + 1]));
} else if(l == 1) printf("%d\n", Sub(1, query(root[0], 1, n, r)));
else printf("%d\n", Sub(1, query(1, 1, n, l - 1, r)));
}
}

P3688 [ZJOI2017] 树状数组 【二维线段树】的更多相关文章

  1. bzoj4785:[ZJOI2017]树状数组:二维线段树

    分析: "如果你对树状数组比较熟悉,不难发现可怜求的是后缀和" 设数列为\(A\),那么可怜求的就是\(A_{l-1}\)到\(A_{r-1}\)的和(即\(l-1\)的后缀减\( ...

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

    题目链接 BZOJ 4785 题解 这道题真是令人头秃 = = 可以看出题面中的九条可怜把求前缀和写成了求后缀和,然后他求的区间和却仍然是sum[r] ^ sum[l - 1],实际上求的是闭区间[l ...

  3. BZOJ4822[Cqoi2017]老C的任务——树状数组(二维数点)

    题目描述 老 C 是个程序员.     最近老 C 从老板那里接到了一个任务——给城市中的手机基站写个管理系统.作为经验丰富的程序员,老 C 轻松 地完成了系统的大部分功能,并把其中一个功能交给你来实 ...

  4. BZOJ1935: [Shoi2007]Tree 园丁的烦恼(树状数组 二维数点)

    题意 题目链接 Sol 二维数点板子题 首先把询问拆成四个矩形 然后离散化+树状数组统计就可以了 // luogu-judger-enable-o2 #include<bits/stdc++.h ...

  5. 树状数组 二维偏序【洛谷P3431】 [POI2005]AUT-The Bus

    P3431 [POI2005]AUT-The Bus Byte City 的街道形成了一个标准的棋盘网络 – 他们要么是北南走向要么就是西东走向. 北南走向的路口从 1 到 n编号, 西东走向的路从1 ...

  6. 树状数组+二维前缀和(A.The beautiful values of the palace)--The Preliminary Contest for ICPC Asia Nanjing 2019

    题意: 给你螺旋型的矩阵,告诉你那几个点有值,问你某一个矩阵区间的和是多少. 思路: 以后记住:二维前缀和sort+树状数组就行了!!!. #define IOS ios_base::sync_wit ...

  7. bzoj 4822: [Cqoi2017]老C的任务【扫描线+树状数组+二维差分】

    一个树状数组能解决的问题分要用树套树--还写错了我别是个傻子吧? 这种题还是挺多的,大概就是把每个矩形询问差分拆成四个点前缀和相加的形式(x1-1,y1-1,1)(x2.y2,1)(x1-1,y2,- ...

  8. 【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询

    Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位 ...

  9. [Usaco2014 Open Gold ]Cow Optics (树状数组+扫描线/函数式线段树)

    这道题一上手就知道怎么做了= = 直接求出原光路和从目标点出发的光路,求这些光路的交点就行了 然后用树状数组+扫描线或函数式线段树就能过了= = 大量的离散+模拟+二分什么的特别恶心,考试的时候是想到 ...

  10. HDU - 1166 树状数组模板(线段树也写了一遍)

    题意: 汉语题就不说题意了,用到单点修改和区间查询(树状数组和线段树都可以) 思路: 树状数组的单点查询,单点修改和区间查询. 树状数组是巧妙运用二进制的规律建树,建树就相当于单点修改.这里面用到一个 ...

随机推荐

  1. SAS学习笔记54 RTF文件格式

    Style RTF Control Word Example Code Italicize \i title '\i italicized title'; Underline \ul title '\ ...

  2. ASCII,UTF-8,Unicode字符串相互转换

    #include<string> #include<windows.h> #include<vector> using namespace std; //utf8 ...

  3. 【SoloPi】SoloPi使用1-初次使用,环境准备(Windows版)

    下载配置Android SDK路径前往 https://developer.android.com/studio/releases/platform-tools#downloads 下载对应系统版本的 ...

  4. http://go.microsoft.com/fwlink/?linkid问题

    今天不知怎的,打开一个网页出现了http://go.microsoft.com/fwlink/?linkid=XXX 烦死了,在百度搜了下方法,什么改注册表,策略模板等不见起效.其实打开IE的设置, ...

  5. JMeter测试HBase

    在网上找了关于jmeter连接hbase的方式,主要分为两种:通过导入jar包连接(Java Request)和通过BeanShell远程连接,由于刚接触jmeter没多久,对BeanShell还不熟 ...

  6. 【SpringMVC】统一异常处理

    一.需求 二.统一异常处理解决方案 2.1 定义异常 2.2 异常处理 2.3 配置统一异常处理器 2.4 异常处理逻辑 一.需求 一般项目中都需要作异常处理,基于系统架构的设计考虑,使用统一的异常处 ...

  7. Django之小结

    常用的函数方法与包的调用 # 登陆视图函数 def login(request): if request.method == 'GET': return render(request,'login.h ...

  8. 极度舒适的 Python 入门教程,小猪佩奇也能学会~

    编程几乎已经成为现代人的一门必修课,特别是 Python ,不仅长期霸占编程趋势榜.薪资榜第一,还屡屡进入小学教材,甚至成为浙江省信息技术高考项目-- 今天,小编带来了一门极度舒适的 Python 入 ...

  9. 基于numpy实现矩阵计算器

    要求 制作一个Python的矩阵计算器: ① 程序提供任意两矩阵的加.乘法运算:方阵的行列式计算.逆矩阵计算.特征分解:任意矩阵的转置等计算功能,可自行添加功能 ② 从控制台通过键盘获取数据并完成以上 ...

  10. 子div撑不开父div的几种解决办法:

    如何修正DIV float之后导致的外部容器不能撑开的问题   在写HTML代码的时候,发现在Firefox等符合W3C标准的浏览器中,如果有一个DIV作为外部容器,内部的DIV如果设置了float样 ...