「ZJOI2019」线段树 解题报告
「ZJOI2019」线段树
听说有人喷这个题简单,然后我就跑去做,然后自闭感++,rp++(雾)
理性分析一波,可以发现最后形成的\(2^k\)个线段树,对应的操作的一个子集,按时间顺序作用到这颗线段树上。
首先考虑研究一下tag的性质,比如两个操作时间先后是否没有影响,操作是否可以以某种形式进行合并,然后啥也没发现。
然后考虑一下一颗树是否可以被压成某个状态,比如实际上只有\(\log\)个状态然后去dp,发现也不行
再次冷静分析一波,发现好像每个节点可以独立考虑,结合上面\(2^n\),不妨考虑转换成概率,算出每个点被打上tag的概率,在数值上同时也是它的期望,这样我们最后乘上线段树个数就好了。
然后这时候就只对一个线段树操作了,考虑咋去搞
这差不多是我做题时的心路历程,但是我写了好几个做法都过不了大样例,十分自闭,总是以为自己没想清楚哪里假了之类的赶紧改过来,结果大样例输出了十几个不同的答案
心态崩了.jpg
又被什么pkuthusc的报名表填的心烦意乱的,就直接去看题解了
发现自己压根没有对节点分类讨论的意识...
设\(dp_i\)表示\(i\)节点被打上标记的概率
考虑对区间\([4,6]\)进行操作后,节点的改变。
后文中,原来的一半因为不变,所以节点改变指变化的那一半的改变。
红色点
有标记也全部被push了
\[dp_i=\frac{dp_i}{2}
\]绿色点
一定被打上标记了
\[dp_i=\frac{dp_i+1}{2}
\]黑色点
考虑它到跟的红色点是不是有一个点给它放标记了,或者原本是它自己的
这个没法直接搞,定义一个辅助数组\(f_i\)表示\(i\)到根至少有一个点有标记的概率
那么有
\[dp_i=\frac{dp_i+f_i}{2}
\]白色点不变
那考虑球一下辅助数组\(f\)
红色点
直接没了
\[f_i=\frac{f_i}{2}
\]绿色点
发现绿色点的子树,都有了一个绿色点,即
\[f_i=\frac{f_i+1}{2}
\]需要实现一个子树加
我们发现形如\(x\leftarrow\frac{x+1}{2}\)的式子,如果进行\(n\)次,会变成\(\frac{x+2^n-1}{2^n}\)
于是可以直接打标记记录一下次数
灰色点
发现有就放到灰色点,没有仍然没有,所以灰色点的子树不变
总复杂度\(O(n\log n)\)
Code:
#include <cstdio>
#include <cctype>
const int SIZE=1<<21;
char ibuf[SIZE],*iS,*iT;
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
template <class T>
void read(T &x)
{
x=0;char c=gc();
while(!isdigit(c)) c=gc();
while(isdigit(c)) x=x*10+c-'0',c=gc();
}
const int mod=998244353;
const int inv2=499122177;
const int N=1e5+10;
#define mul(a,b) (1ll*(a)*(b)%mod)
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
#define ls id<<1
#define rs id<<1|1
int fdp[N<<2],dp[N<<2],sum[N<<2],tag[N<<2];
int n,m,in2[N];
void updata(int id)
{
sum[id]=add(add(sum[ls],sum[rs]),dp[id]);
}
void pushdown(int id)
{
tag[ls]+=tag[id];
tag[rs]+=tag[id];
fdp[ls]=add(mul(fdp[ls],in2[tag[id]]),add(1,mod-in2[tag[id]]));
fdp[rs]=add(mul(fdp[rs],in2[tag[id]]),add(1,mod-in2[tag[id]]));
tag[id]=0;
}
void modify(int id,int L,int R,int l,int r)
{
if(l==L&&r==R)
{
sum[id]=add(sum[id],mod-dp[id]);
dp[id]=mul(dp[id]+1,inv2);
fdp[id]=mul(fdp[id]+1,inv2);
sum[id]=add(sum[id],dp[id]);
++tag[id];
return;
}
dp[id]=mul(dp[id],inv2);
fdp[id]=mul(fdp[id],inv2);
pushdown(id);
int Mid=L+R>>1;
if(r<=Mid)
{
sum[rs]=add(sum[rs],mod-dp[rs]);
dp[rs]=mul(add(dp[rs],fdp[rs]),inv2);
sum[rs]=add(sum[rs],dp[rs]);
modify(ls,L,Mid,l,r);
}
else if(l>Mid)
{
sum[ls]=add(sum[ls],mod-dp[ls]);
dp[ls]=mul(add(dp[ls],fdp[ls]),inv2);
sum[ls]=add(sum[ls],dp[ls]);
modify(rs,Mid+1,R,l,r);
}
else
modify(ls,L,Mid,l,Mid),modify(rs,Mid+1,R,Mid+1,r);
updata(id);
}
int main()
{
read(n),read(m);
in2[0]=1;
for(int i=1;i<=n;i++) in2[i]=mul(in2[i-1],inv2);
for(int t=1,op,l,r,i=1;i<=m;i++)
{
read(op);
if(op==1)
{
read(l),read(r);
modify(1,1,n,l,r);
t=add(t,t);
}
else printf("%lld\n",mul(sum[1],t));
}
return 0;
}
2019.5.10
「ZJOI2019」线段树 解题报告的更多相关文章
- 【LOJ】#3043. 「ZJOI2019」线段树
LOJ#3043. 「ZJOI2019」线段树 计数转期望的一道好题-- 每个点设两个变量\(p,q\)表示这个点有\(p\)的概率有标记,有\(q\)的概率到祖先的路径上有个标记 被覆盖的点$0.5 ...
- 「SHOI2014」三叉神经树 解题报告
「SHOI2014」三叉神经树 膜拜神仙思路 我们想做一个类似于动态dp的东西,首先得确保我们的运算有一个交换律,这样我们可以把一长串的运算转换成一块一块的放到矩阵上之类的东西,然后拿数据结构维护. ...
- LOJ 3043: 洛谷 P5280: 「ZJOI2019」线段树
题目传送门:LOJ #3043. 题意简述: 你需要模拟线段树的懒标记过程. 初始时有一棵什么标记都没有的 \(n\) 阶线段树. 每次修改会把当前所有的线段树复制一份,然后对于这些线段树实行一次区间 ...
- 「ZJOI2019」线段树
传送门 Description 线段树的核心是懒标记,下面是一个带懒标记的线段树的伪代码,其中 tag 数组为懒标记: 其中函数\(Lson(Node)\)表示\(Node\)的左儿子,\(Rson( ...
- 【LOJ3043】「ZJOI2019」线段树
题面 问题可以转化为每次区间覆盖操作有 \(\frac{1}{2}\) 的概率进行,求标记和的期望.于是我们只要求出所有点有标记的概率即可. 我们设 \(f_i\) 表示节点 \(i\) 有标记的概率 ...
- @loj - 3043@「ZJOI2019」线段树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 九条可怜是一个喜欢数据结构的女孩子,在常见的数据结构中,可怜最喜 ...
- 「模板」 线段树——区间乘 && 区间加 && 区间求和
「模板」 线段树--区间乘 && 区间加 && 区间求和 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long l ...
- Loj #2570. 「ZJOI2017」线段树
Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...
- 「ZJOI2016」大森林 解题报告
「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...
随机推荐
- MySQL UNSIGNED
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11484087.html UNSIGNED属性就是将数字类型无符号化,与C.C++这些程序语言中的uns ...
- Cisco基础(五):配置静态NAT、配置端口映射、配置动态NAT、PAT配置、办公区Internet的访问
一.配置静态NAT 目标: 随着接入Internet的计算机数量的不断猛增,IP地址资源也就愈加显得捉襟见肘.事实上,除了中国教育和科研计算机网(CERNET)外,一般用户几乎申请不到整段的C类IP地 ...
- 【Java架构:基础技术】一篇文章搞掂:MyBatis-Plus
前言 Mybatis:一个流行的半自动ORM框架. Mybatis-Plus:一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发.提高效率而生. 本文使用的版本:myb ...
- 团队冲刺DAY4
DES算法 算法概要 在DES.java当中创立两个方法分别用作加密和解密 通过 `public static byte[] encrypt(byte[] data, String sKey) 创建方 ...
- (转)使用OpenGL ES显示图像
编写:jdneo - 原文:http://developer.android.com/training/graphics/opengl/index.html 转:http://hukai.me/and ...
- Java关于Math类的三个取整方法
0x01 在java的Math类中有三个关于浮点数取整数的方法,分别是ceil (向上取整) floor(向下取整) round(四舍五入) 三个方法 0x02 ceil 向上取整,取整后总是比原来的 ...
- Find a Way (双bfs)
Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year ...
- python作业/练习/实战:2、注册、登录(文件读写操作)
作业要求 1.实现注册功能输入:username.passowrd,cpassowrd最多可以输错3次3个都不能为空用户名长度最少6位, 最长20位,用户名不能重复密码长度最少8位,最长15位两次输入 ...
- VS2008的使用
文章转载自:http://www.cnblogs.com/aduck/archive/2011/11/11/2245460.html 1.如何在vc2008中显示行号 中文版: 菜单-工具-选项 在新 ...
- 数据转化之JSON
1.定义:Json(JavaScript Object Notation)是一种轻量级的数据教换模式,简单来说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结 ...