P3688 [ZJOI2017] 树状数组 【二维线段树】

时间:2023-01-19 22:37:03

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

P3688 [ZJOI2017] 树状数组 【二维线段树】

有两种共\(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&colon;&lbrack;ZJOI2017&rsqb;树状数组&colon;二维线段树

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

  2. BZOJ 4785 &lbrack;Zjoi2017&rsqb;树状数组 &vert; 二维线段树

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

  3. BZOJ4822&lbrack;Cqoi2017&rsqb;老C的任务——树状数组&lpar;二维数点&rpar;

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

  4. BZOJ1935&colon; &lbrack;Shoi2007&rsqb;Tree 园丁的烦恼&lpar;树状数组 二维数点&rpar;

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

  5. 树状数组 二维偏序【洛谷P3431】 &lbrack;POI2005&rsqb;AUT-The Bus

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

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

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

  7. bzoj 4822&colon; &lbrack;Cqoi2017&rsqb;老C的任务【扫描线&plus;树状数组&plus;二维差分】

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

  8. 【BZOJ3110】【整体二分&plus;树状数组区间修改&sol;线段树】K大数查询

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

  9. &lbrack;Usaco2014 Open Gold &rsqb;Cow Optics &lpar;树状数组&plus;扫描线&sol;函数式线段树&rpar;

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

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

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

随机推荐

  1. jQuery里ajax的用法

    $.ajax({ type:'post',//这里页面数据发送请求的方式可以为post和get cache:'false ', //这里可以为false或者true 是否要缓存 ,默认为false u ...

  2. Nagios Core&sol;Icinga 基于栈的缓冲区溢出漏洞

    漏洞名称: Nagios Core/Icinga 基于栈的缓冲区溢出漏洞 CNNVD编号: CNNVD-201402-484 发布时间: 2014-03-03 更新时间: 2014-03-03 危害等 ...

  3. 2&period;Visual Studio 2013中的默认快捷键

    这篇大致是IDE的使用技巧,常用的也就那么几个. 我自己用的最多的是注释.取消注释.格式调整.运行测试.开始调试.断开调试.重新开始调试.删除行ctrl+L.保存.全部保存.打开资源管理器.搜索等几个 ...

  4. python实现散列表的链表法

    在散列中,链接法是一种最简单的碰撞解决技术,这种方法的原理就是把散列到同一槽中的所有元素 都放在一个链表中. 链接法有两个定理,定理一: 在简单一致散列的假设下,一次不成功查找的期望时间为O(1 + ...

  5. sql server 阻塞查询

    在生产环境下,有时公司客服反映网页半天打不到,除了在浏览器按F12的Network响应来排查,确定web服务器无故障后.就需要检查数据库是否有出现阻塞 当时数据库的生产环境中主表数据量超过2000w, ...

  6. H&period;264采集、编码、传输的流程

    转载自H.264采集.编码.传输的流程 1 采集到的原始数据放入buf中 2 转化为yuv格式放入yuv conv.RGB24_to_YV12(buf, yuv,IMAGE_WIDTH, IMAGE_ ...

  7. python高效学习路线图

  8. 数据存储之 SharedPreference 共享参数 &lpar;转&rpar;

        在上一讲中,我们学习了如何将数据存储在SD卡中[数据存储之File文件存储 [即SD卡的写入与读取]],这是一种存储方式,这一讲我们来学习一下使用SharedPreferences存储数据. ...

  9. CentOS-pam认证机制简介

    前言 linux下PAM模块全称是Pluggable Authentication Module for linux(可插入式授权管理模块),该由Sun公司提供,在Linux中,PAM是可动态配置的, ...

  10. 浅谈SQL Server中的三种物理连接操作&lpar;Nested Loop Join、Merge Join、Hash Join&rpar;

    简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...