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

吉老师的题目真是难想。。。

代码中求的是 \(\sum_{i=l-1}^{r-1}a_i\),而实际求的是 \(\sum_{i=l}^{r}a_i\),所以我们直接判断 \(a_{l-1}\) 和 \(a_r\) 是否相等就行了。

我们用二维线段树,一维存左端点 \(l\),一维存右端点 \(r\),里面存 \(a_l=a_r\) 的概率。

若 \(a\in [1,l-1],b\in [l,r]\),操作不在 \(b\),概率为 \(1-p\)

若 \(a\in [l,r],b\in [l,r]\),操作不在 \(a\) 和 \(b\),概率为 \(1-2\times p\)

若 \(a\in [r+1,n],b\in [l,r]\),操作不在 \(b\),概率为 \(1-p\)

如果左边相等的概率是 \(p\),右边相等的概率是 \(q\),那么总概率是 \(p\times q+(1-p)\times (1-q)\)

我们标记永久化一下就能做到 \(O(n\log^2 n)\)

但是有问题!\(l=1\) 时求的是前缀和等于后缀和的概率!

那么我们多开一棵线段树记录前缀和等于后缀和的概率。

若 \(a\in [1,l-1]\),没有操作满足,概率为 \(0\)

若 \(a\in [l,r]\),操作刚好在 \(a\),概率为 \(p\)

若 \(a\in [r+1,n]\),没有操作满足,概率为 \(0\)

所以仔细一看是一个二合一的题目。。。

\(Code\ Below:\)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100000+10;
const int mod=998244353;
int n,m,T[maxn<<2],tot; /*
a -> [1, l - 1] b -> [l, r] 1 - p
a -> [l, r] b -> [l, r] 1 - 2 * p
a -> [r + 1, n] b -> [l, r] 1 - p
a -> [0, 0] b -> [1, l - 1] 0
a -> [0, 0] b -> [l, r] p
a -> [0, 0] b -> [r + 1, n] 0
*/ struct node{
int ls,rs,val;
inline void init(){ls=rs=0,val=1;}
}t[maxn*400]; inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
} inline int fpow(int a,int b){
int ret=1;
for(;b;b>>=1,a=1ll*a*a%mod)
if(b&1) ret=1ll*ret*a%mod;
return ret;
} inline int merge(int x,int y){
return (1ll*x*y+1ll*(mod+1ll-x)*(mod+1ll-y))%mod;
} namespace ST{
void update(int &x,int L,int R,int C,int l,int r){
if(!x) x=++tot,t[x].init();
if(L <= l && r <= R){t[x].val=merge(t[x].val,C);return;}
int mid=(l+r)>>1;
if(L <= mid) update(t[x].ls,L,R,C,l,mid);
if(R > mid) update(t[x].rs,L,R,C,mid+1,r);
}
int query(int x,int l,int r,int k){
if(!x) return 1;
if(l == r) return t[x].val;
int mid=(l+r)>>1;
if(k <= mid) return merge(t[x].val,query(t[x].ls,l,mid,k));
else return merge(t[x].val,query(t[x].rs,mid+1,r,k));
}
} #define lson (rt<<1)
#define rson (rt<<1|1) void update(int L,int R,int x,int y,int v,int l,int r,int rt){
if(L <= l && r <= R){ST::update(T[rt],x,y,v,0,n);return;}
int mid=(l+r)>>1;
if(L <= mid) update(L,R,x,y,v,l,mid,lson);
if(R > mid) update(L,R,x,y,v,mid+1,r,rson);
} int query(int x,int y,int l,int r,int rt){
if(l == r) return ST::query(T[rt],0,n,y);
int mid=(l+r)>>1;
if(x <= mid) return merge(ST::query(T[rt],0,n,y),query(x,y,l,mid,lson));
else return merge(ST::query(T[rt],0,n,y),query(x,y,mid+1,r,rson));
} int main()
{
n=read(),m=read();
int op,l,r,p;
while(m--){
op=read(),l=read(),r=read();
if(op==1){
p=fpow(r-l+1,mod-2);
update(l,r,l,r,(mod+1-2*p%mod)%mod,0,n,1);
update(0,0,l,r,p,0,n,1);
if(l>1){
update(1,l-1,l,r,(mod+1-p)%mod,0,n,1);
update(0,0,1,l-1,0,0,n,1);
}
if(r<n){
update(l,r,r+1,n,(mod+1-p)%mod,0,n,1);
update(0,0,r+1,n,0,0,n,1);
}
}
if(op==2) printf("%d\n",query(l-1,r,0,n,1));
}
return 0;
}

「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. Centos7系统安装部署docker

    一.安装docker #创建docker相关的目录 mkdir -p /data/docker #安装docker运行必要工具 sudo yum install -y yum-utilsdevice- ...

  2. vue iview render里面写时间截取

    render: (h, params) => {params.row.execDate = (params.row.execDate ? params.row.execDate.substr(0 ...

  3. Qt跨平台开发Wince5.0和Android程序

    所谓跨平台是指维护一份代码,可编译出多平台的应用程序.Qt这方面虽然已经做的不错,但性能还是体验,和原生开发工具开发的程序相比,差距还是不小的.但单从生产应用的角度来说,可以采用,不失为一种好的解决方 ...

  4. rn最新版测试

    1.使用软件版本rn-4.20.4.zipdrago-4.22.03 2.启动drago选择菜单‘对弈’ -> ‘对弈引擎设置’,点按钮‘添加’,选择‘已安装’,输入:姓名‘rn-4.20.4’ ...

  5. U-Mail企业邮箱如何导入授权文件

    首先,由于U-Mail有Linux版本与Windows版本的区别,并且都非常简单,所以就有了下面的步骤: Windows版本  <点击快速跳转> Linux版本 <点击快速跳转> ...

  6. 在html中使用javascript总结

    对于初学者运行代码的第一步,首先是怎么把你所写的js代码与html代码之间关联起来,只有关联了,js才能控制html中的代码,进而达到控制页面的目的,我总结了html引用js的方法,一方面可以时时复习 ...

  7. 关于get和post请求的区别

    1.标准答案 GET在浏览器回退时是无害的,而POST会再次提交请求. GET产生的URL地址可以被Bookmark,而POST不可以. GET请求会被浏览器主动cache,而POST不会,除非手动设 ...

  8. .gvfs: Permission denied

    命令行输入umount .gvfs rm -rf .gvfs

  9. table增删改查操作--jq

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  10. Codeforces Codeforces Round #484 (Div. 2) E. Billiard

    Codeforces Codeforces Round #484 (Div. 2) E. Billiard 题目连接: http://codeforces.com/contest/982/proble ...