「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;
}

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

  1. 「ZJOI2017」树状数组(二维线段树)

    「ZJOI2017」树状数组(二维线段树) 吉老师的题目真是难想... 代码中求的是 \(\sum_{i=l-1}^{r-1}a_i\),而实际求的是 \(\sum_{i=l}^{r}a_i\),所以 ...

  2. UOJ#291. 【ZJOI2017】树状数组 树套树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ291.html 题解 结论:这个写错的树状数组支持的是后缀加和后缀求和.这里的后缀求和在 x = 0 的时 ...

  3. 【ZJOI2017】树状数组

    题目描述 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的 OI 比赛经历.那是一道基础的树状数组题. 给出一个长度为 $n$ 的数组 $A$,初始值都为 $0$,接下来 ...

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

    $ \color{#0066ff}{ 题目描述 }$ 「Hanabi, hanabi--」 一听说祭典上没有烟火,Karen 一脸沮丧. 「有的哦-- 虽然比不上大型烟花就是了.」 还好 Shinob ...

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

    学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2 ...

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

    1A,拿来练手的好题 用一个优先队列按煮熟时间从小到大排序,被煮熟了就弹出来. 用n个vector维护每种食物的煮熟时间,显然是有序的. 用树状数组维护每种煮熟食物的数量. 每次操作前把优先队列里煮熟 ...

  7. 【loj6041】「雅礼集训 2017 Day7」事情的相似度 后缀自动机+STL-set+启发式合并+离线+扫描线+树状数组

    题目描述 给你一个长度为 $n$ 的01串,$m$ 次询问,每次询问给出 $l$ .$r$ ,求从 $[l,r]$ 中选出两个不同的前缀的最长公共后缀长度的最大值. $n,m\le 10^5$ 题解 ...

  8. 「模拟赛20180306」回忆树 memory LCA+KMP+AC自动机+树状数组

    题目描述 回忆树是一棵树,树边上有小写字母. 一次回忆是这样的:你想起过往,触及心底--唔,不对,我们要说题目. 这题中我们认为回忆是这样的:给定 \(2\) 个点 \(u,v\) (\(u\) 可能 ...

  9. 「模拟赛20180307」三元组 exclaim 枚举+树状数组

    题目描述 给定 \(n,k\) ,求有多少个三元组 \((a,b,c)\) 满足 \(1≤a≤b≤c≤n\)且\(a + b^2 ≡ c^3\ (mod\ k)\). 输入 多组数据,第一行数据组数\ ...

随机推荐

  1. css的鼠标手势总结

    css的鼠标手势 cursor:pointer; 或 cursor:hand : 手型 cursor:crosshair : 十字 cursor:text : 文本 cursor:wait : 等待 ...

  2. null和空字符串对于查询where条件语句的影响

    在数据库中我们进行数据处理的过程中,对于null值或者空字符串的情况对于这种数据我们进行计算平均值以及查询过程中如何进行对于这类数据的处理呢? step1:建表:create table a(id i ...

  3. Linux_Cornd任务调度

    Crond任务调度 进行定时任务的设置 概述 任务调度:是指系统在某个时间执行特定的命令或程序 作用:避免重复工作 基本语法 crontab [选项] 选项 功能 -e 编辑crontab定时任务 - ...

  4. 【MySQL作业】sum、max 和 min 聚合函数——美和易思聚合函数应用习题

    点击打开所使用到的数据库>>> 1.统计商品最高单价和最低单价. -- 获取所有商品的最高单价和最低单价: select max(unitPrice) 最高单价 , min(unit ...

  5. 编写Java程序,用户在网上购买商品(good),当用户买了一本书(book)、一顶帽子(hat)或者买了一双鞋子(shoe),卖家就会通过物流将商品邮寄给用户,使用简单工厂模式模拟这一过程。

    查看本章节 查看作业目录 需求说明: 编写Java程序,用户在网上购买商品(good),当用户买了一本书(book).一顶帽子(hat)或者买了一双鞋子(shoe),卖家就会通过物流将商品邮寄给用户, ...

  6. Spring @Component 注解的使用

    使用说明 这个注解用于声明当前的类是一个组件类,Spring 会通过类路径扫描来自动侦测和自动装配这些组件,创建一个个 bean 后,注册到 Spring 容器中. 带 @Component 注解的类 ...

  7. js 表格操作 全选和反选效果 案例

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  8. Linux 进程调度

    线程状态(context) 程序计数器(Program Counter),它表示当前线程执行指令的位置. 保存变量的寄存器. 程序的Stack.通常来说每个线程都有属于自己的Stack,Stack记录 ...

  9. Linux系统使用crt登录之后如何显示横幅消息

    打开  /etc/motd 编辑内容即可 效果如下

  10. nmap高级用法

    nmap在信息收集中起着很大的作用,今天我来总结一些nmap常用的一些命令 常用探测主机存活方式 1.-sP:进行ping扫描 打印出对ping扫描做出响应的主机,不做进一步测试(如端口扫描或者操作系 ...