洛谷P3688/uoj#291. [ZJOI2017]树状数组
这里是题解以及我的卡常数历程
话说后面那几组数据莫不是lxl出的这么毒
首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间和。因为模\(2\)意义下的加法就是异或,所以错误查询和正确查询相等就意味着\(a[l-1]\)和\(a[r]\)相等
我们不能简单的维护每个位置是什么值的概率,比方说一次修改了\([1,2]\),虽然这两个位置为\(1\)的概率都是\(\frac{1}{1}\),但它们的值绝对不相等
所以我们需要维护二元组\((x,y)\)代表\(x\)和\(y\)相等的概率,需要开一个二维线段树(我到今天才知道原来二维线段树该这么写……以前一直都是一个父亲四个儿子……)
那么对于一次修改操作\((l,r)\),会发生改变的二元组有
1.左端点在\([1,l-1]\)之间,右端点在\([l,r]\)之间
2.左端点在\([l,r]\)之间,右端点在\([r+1,n]\)之间
3.左右端点都在\([l,r]\)之间
设区间长度为\(len\),那么对于\(1,2\),这次操作有\(\frac{1}{len}\)的概率使它们取反,对于\(3\)操作,这次操作有\(\frac{2}{len}\)的概率使它们取反
关于标记合并的问题的话,如果设两次取反的概率分别为\(p,q\),那么最终被取反的概率为\(p(1-q)+q(1-p)\)
然而我们需要特判\(l=1\)的情况,因为按题目中的树状数组的写法此时会返回\(0\),所以这个时候就是查询\([1,l-1]\)和\([r+1,n]\)是否相等,我们可以单独开一个一维线段树,对每个位置\(i\)维护\([1,i-1]\)和\([i+1,n]\)相等的概率,需要的时候在线段树上查询就是了
接下来是卡常问题
首先是标记永久化,即我们在线段树上打标记的时候不下传,而是直接叠在那一层,查询的时候把经过路径上的所有标记直接加到答案上去
其次,对于答案和询问的左右端点,我们不传参,直接开全局变量
再者,一维线段树上,在\(r-l+1\leq 7\)的时候我们不继续递归下去而是改成暴力打标记
最后,我们维护有序的二元组\((x,y)\)的时候令\(x<y\),所以在二维线段树上打标记的时候不用去管第二维里比第一维小的那部分
什么读优输优手打\(max\)之类的我就不多说了……
//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5,P=998244353,M=4e7+5;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
inline int calc(R int x,R int y){return (1ll*x*(P+1-y)%P+1ll*y*(P+1-x)%P)%P;}
inline int max(const R int &x,const R int &y){return x>y?x:y;}
inline int min(const R int &x,const R int &y){return x<y?x:y;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
int n,m,ans,op,l,r,len,inv[N],x,y;
struct tree1{
int rt[N<<2],val[M],ls[M],rs[M],a[N],cnt;
void ins(int &p,int l,int r,int ql,int qr,int v){
if(!p)p=++cnt;
if(ql<=l&&qr>=r)return val[p]=calc(val[p],v),void();
int mid=(l+r)>>1;
if(ql<=mid)ins(ls[p],l,mid,ql,qr,v);
if(qr>mid)ins(rs[p],mid+1,r,ql,qr,v);
}
void query(int p,int l,int r){
if(!p)return;ans=calc(ans,val[p]);
if(l==r)return;int mid=(l+r)>>1;
y<=mid?query(ls[p],l,mid):query(rs[p],mid+1,r);
}
void qins(int p,int l,int r,int ql,int qr,int dl,int dr,int v){
if(ql<=l&&qr>=r)return ins(rt[p],1,n,max(dl,l),dr,v);
int mid=(l+r)>>1;
if(ql<=mid)qins(p<<1,l,mid,ql,qr,dl,dr,v);
if(qr>mid)qins(p<<1|1,mid+1,r,ql,qr,dl,dr,v);
}
void qquery(int p,int l,int r){
query(rt[p],1,n);
if(l==r)return;int mid=(l+r)>>1;
x<=mid?qquery(p<<1,l,mid):qquery(p<<1|1,mid+1,r);
}
}T;
struct tree2{
int val[N<<2],a[N];
void update(int l,int r,int v){fp(i,l,r)a[i]=calc(a[i],v);}
void ins(int p,int l,int r,int ql,int qr,int v){
if(r-l+1<=7)return update(max(ql,l),min(qr,r),v);
if(ql<=l&&qr>=r)return val[p]=calc(val[p],v),void();
int mid=(l+r)>>1;
if(ql<=mid)ins(p<<1,l,mid,ql,qr,v);
if(qr>mid)ins(p<<1|1,mid+1,r,ql,qr,v);
}
void query(int p,int l,int r){
if(r-l+1<=7)return ans=calc(ans,a[x]),void();
ans=calc(ans,val[p]);
if(l==r)return;int mid=(l+r)>>1;
x<=mid?query(p<<1,l,mid):query(p<<1|1,mid+1,r);
}
}G;
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read();
inv[0]=inv[1]=1;fp(i,2,n)inv[i]=1ll*inv[P%i]*(P-P/i)%P;
while(m--){
op=read(),l=read(),r=read();
if(op==1){
len=r-l+1;
if(l>1)T.qins(1,1,n,1,l-1,l,r,inv[len]),G.ins(1,1,n,1,l-1,1);
if(r<n)T.qins(1,1,n,l,r,r+1,n,inv[len]),G.ins(1,1,n,r+1,n,1);
if(l!=r)T.qins(1,1,n,l,r,l,r,mul(2,inv[len])),G.ins(1,1,n,l,r,dec(1,inv[len]));
}else{
ans=1;
if(l==1)x=r,G.query(1,1,n);
else x=l-1,y=r,T.qquery(1,1,n);
print(ans);
}
}return Ot(),0;
}
洛谷P3688/uoj#291. [ZJOI2017]树状数组的更多相关文章
- [洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?
其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客 Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数 ...
- 洛谷P3368 【模板】树状数组 2
P3368 [模板]树状数组 2 102通过 206提交 题目提供者HansBug 标签 难度普及/提高- 提交 讨论 题解 最新讨论 暂时没有讨论 题目描述 如题,已知一个数列,你需要进行下面两 ...
- 洛谷P3374 【模板】树状数组 1
P3374 [模板]树状数组 1 140通过 232提交 题目提供者HansBug 标签 难度普及/提高- 提交 讨论 题解 最新讨论 题目描述有误 题目描述 如题,已知一个数列,你需要进行下面两 ...
- 洛谷 P3368 【模板】树状数组 2
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 洛谷 P3374 【模板】树状数组 1
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 树状数组模板(pascal) 洛谷P3374 【模板】树状数组1
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 洛谷 P3368 【模板】树状数组 2(区间修改点查询)
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 洛谷 P3368 【模板】树状数组 2 题解
P3368 [模板]树状数组 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入格式 第一行包含两个整数N.M,分别表示该数列数字的个 ...
- 洛谷 P3374 【模板】树状数组 1 题解
P3374 [模板]树状数组 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入格式 第一行包含两个整数N.M,分别表示该数列数字的个数 ...
随机推荐
- matlab 在机器视觉中常用的函数
~ triangulate() 三角化(获得距离)匹配点 ~ undistortImage() 去除相机畸变并生成图像
- 剑指Offer:数组中出现次数超过一半的数字【39】
剑指Offer:数组中出现次数超过一半的数字[39] 题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于这 ...
- okhttp 请求list数据实例
public class DataBean { /** * id : 61684 * movieName : <猜火车2>先导预告片 * coverImg : http://img31.m ...
- ssh免密登陆服务器
本文介绍的是以公钥认证的方式实现 ssh 免密码登陆远程服务器. 客户端生成RSA公钥和私钥 在用户更目录有一个 .ssh 的文件夹,如果没有就新建一个.在文件夹中通过命令 ssh-keygen -t ...
- SPOJ - SUBST1 New Distinct Substrings —— 后缀数组 单个字符串的子串个数
题目链接:https://vjudge.net/problem/SPOJ-SUBST1 SUBST1 - New Distinct Substrings #suffix-array-8 Given a ...
- js动态插入标签代码(insertAdjacentHTML)
做网页时通过ajax请求获取到数据后,有的需要把数据拼接到带有各种标签的字符串中,拼接完字符串就需要把字符串动态添加到网页上的某个位置,举个
- ubuntu14开发环境配置
1 配置JDK1.8 jdk工具从官网下载,我下载到了~/tool目录下,首先进入用户的bash配置目录,打开配置文件: cd ~ vi .bashrc 编辑.bashrc文件,在适当位置或者文件最后 ...
- 9--RESTful支持
1.对url进行规范,写RESTful格式的url 非REST的url:http://...../queryItems.action?id=001&type=T01 REST的url风格:ht ...
- BZOJ 1192 [HNOI2006]鬼谷子的钱袋:二进制 砝码称重问题
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1192 题意: 鬼谷子带了a元钱,他要把a元钱分装在小袋子中,使得任意不大于a的数目的钱,都 ...
- JavaScript中函数的无限次运算问题
开博客有一段时间了,一直没动笔,原因是确实没看到什么值得写的内容.直到今天在司徒正美的博客里看到一个问题. http://www.cnblogs.com/rubylouvre/archive/2012 ...