送我退役的神题,但不得不说是ZJOIDay1最可做的一题了

先说一下考场的ZZ想法以及出来后YY的优化版吧

首先发现每次操作其实就是统计出增加的节点个数(原来的不会消失)

所以我们只要统计出线段树上每个节点在进行了\(t\)次操作(有\(2^t\)棵树)是某个点为\(1\)的总个数,令这个值为\(f_x\)

然后考场上用了一种记录该节点+左儿子+右儿子状态的方法,这样可以把答案的贡献全部算到这个点上

但是这样细节巨多且容易算重(漏),所以考场上码了\(200+\)行最后没调出大样例

后来想了一种记录该节点+父亲状态的方法,但是这样贡献就要算重,可能可以利用矩阵来做

接下来我们考虑正解,我们发现细分每一个点的性质其实就只有\(4\)种:

  1. 直接在该点进行赋值操作,那么此时显然多出的\(2^{t-1}\)棵树的这个节点都是可行的,直接\(f_x+=2^{t-1}\)
  2. 直接在该点进行pushdown,那么此时显然多出的树上这个点没有增加(\(1\to 0\)了,\(0\)还是\(0\)),\(f_x\)不变
  3. 该点不在修改区间内,那么状态直接被复制一遍,\(f_x*=2\)
  4. 最麻烦的一种,该点(包括这个点)到根的路径上至少有一个点的tag为\(1\),我们令这个方案数为\(g_x\),那么就有\(f_x+=g_x\)

然后开始考虑怎么维护\(g_x\),那么类似地分成\(3\)类讨论:

  1. 直接在该点进行pushdown,那么新增的树的这个节点到根的路径上都不会tag等于\(1\)的情况,\(g_x\)不变
  2. 直接再该点打标记,多出的\(2^{t-1}\)棵树中它的子树内的点显然都有\(g_x+=2^{t-1}\)
  3. 该点被访问但不在区间内,和上面一样,直接\(g_x*=2\)

那么我们显然还是可以用线段树来维护\(f,g\),具体考虑到修改\(g\)的时候要集体\(*2\)不好维护(其实开一个乘法标记和两个加法标记即可),我们直接在最外面乘上\(2^t\),然后把访问过的节点都\(\div2\)即可

然后\(g\)的标记怎么下传呢,我们发现可以再开一个懒标记\(tag\)表示这个点有多少次直接修改,然后下传的时候用这个来改\(g\)

具体地就是先把该除的\(2\)除了,然后加上\(\frac{1}{2}+\frac{1}{4}+\frac{1}{8}+\dots+\frac{1}{2^{tag}}=1-\frac{1}{2^{tag}}\)即可

附上超级简短的CODE

  1. #include<cstdio>
  2. #include<cctype>
  3. #define RI register int
  4. #define CI const int&
  5. #define Tp template <typename T>
  6. using namespace std;
  7. const int N=100005,mod=998244353,inv2=499122177;
  8. int n,m,opt,x,y,ipw[N],ret,prod;
  9. class FileInputOutput
  10. {
  11. private:
  12. static const int S=1<<21;
  13. #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
  14. #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
  15. char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
  16. public:
  17. Tp inline void read(T& x)
  18. {
  19. x=0; char ch; while (!isdigit(ch=tc()));
  20. while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
  21. }
  22. Tp inline void write(T x)
  23. {
  24. if (!x) return (void)(pc('0'),pc('\n')); RI ptop=0;
  25. while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n');
  26. }
  27. inline void Fend(void)
  28. {
  29. fwrite(Fout,1,Ftop,stdout);
  30. }
  31. #undef tc
  32. #undef pc
  33. }F;
  34. inline void inc(int& x,CI y)
  35. {
  36. if ((x+=y)>=mod) x-=mod;
  37. }
  38. inline void dec(int& x,CI y)
  39. {
  40. if ((x-=y)<0) x+=mod;
  41. }
  42. inline int sum(CI x,CI y)
  43. {
  44. int t=x+y; return t>=mod?t-mod:t;
  45. }
  46. inline int sub(CI x,CI y)
  47. {
  48. int t=x-y; return t<0?t+mod:t;
  49. }
  50. class Segment_Tree
  51. {
  52. private:
  53. struct segment
  54. {
  55. int f,g,tag;
  56. }node[N<<2];
  57. #define F(x) node[x].f
  58. #define G(x) node[x].g
  59. #define T(x) node[x].tag
  60. inline void pushdown(CI now)
  61. {
  62. if (!T(now)) return; int& add=T(now); T(now<<1)+=add; T(now<<1|1)+=add;
  63. G(now<<1)=sum(1LL*G(now<<1)*ipw[add]%mod,sub(1,ipw[add]));
  64. G(now<<1|1)=sum(1LL*G(now<<1|1)*ipw[add]%mod,sub(1,ipw[add])); add=0;
  65. }
  66. public:
  67. inline void modify(CI beg,CI end,CI now=1,CI l=1,CI r=n)
  68. {
  69. dec(ret,F(now)); F(now)=1LL*F(now)*inv2%mod; G(now)=1LL*G(now)*inv2%mod;
  70. if (beg<=l&&r<=end) inc(F(now),inv2),inc(G(now),inv2);
  71. if (l>end||r<beg) inc(F(now),G(now)),inc(G(now),G(now)); inc(ret,F(now));
  72. if (l>end||r<beg) return; if (beg<=l&&r<=end) return (void)(++T(now));
  73. pushdown(now); int mid=l+r>>1; modify(beg,end,now<<1,l,mid); modify(beg,end,now<<1|1,mid+1,r);
  74. }
  75. #undef F
  76. #undef G
  77. #undef T
  78. }SEG;
  79. int main()
  80. {
  81. //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
  82. RI i; for (F.read(n),F.read(m),ipw[0]=i=1;i<=m;++i)
  83. ipw[i]=1LL*ipw[i-1]*inv2%mod; for (i=prod=1;i<=m;++i)
  84. {
  85. F.read(opt); if (opt^1) F.write(1LL*ret*prod%mod);
  86. else inc(prod,prod),F.read(x),F.read(y),SEG.modify(x,y);
  87. }
  88. return F.Fend(),0;
  89. }

Luogu P5280 [ZJOI2019]线段树的更多相关文章

  1. 洛谷P5280 [ZJOI2019]线段树

      https://www.luogu.org/problemnew/show/P5280 省选的时候后一半时间开这题,想了接近两个小时的各种假做法,之后想的做法已经接近正解了,但是有一些细节问题理不 ...

  2. P5280 [ZJOI2019]线段树

    题目链接:洛谷 题目描述:[比较复杂,建议看原题] 这道题太神仙了,线段树上做树形dp. 根据树形dp的套路,都是按照转移的不同情况给节点分类.这里每次modify的时候对于节点的影响也不同,所以我们 ...

  3. 洛谷 P5280 - [ZJOI2019]线段树(线段树+dp,神仙题)

    题面传送门 神仙 ZJOI,不会做啊不会做/kk Sooke:"这八成是考场上最可做的题",由此可见 ZJOI 之毒瘤. 首先有一个非常显然的转化,就是题目中的"将线段树 ...

  4. 洛谷P5280 [ZJOI2019]线段树 [线段树,DP]

    传送门 无限Orz \(\color{black}S\color{red}{ooke}\)-- 思路 显然我们不能按照题意来每次复制一遍,而多半是在一棵线段树上瞎搞. 然后我们可以从\(modify\ ...

  5. 洛谷P5280 [ZJOI2019]线段树(线段树)

    题面 传送门 题解 考场上就这么一道会做的其它连暴力都没打--活该爆炸-- 首先我们得看出问题的本质:有\(m\)个操作,总共\(2^m\)种情况分别对应每个操作是否执行,求这\(2^m\)棵线段树上 ...

  6. [Luogu5280][ZJOI2019]线段树(线段树+DP)

    https://www.luogu.org/blog/Sooke/solution-p5280 首先想到对线段树上每个点分别维护有多少棵线段树在它上有标记(f[]),然后想到对于每个操作,根据转移的不 ...

  7. [Luogu] 可持久化线段树 1(主席树)

    https://www.luogu.org/problemnew/show/P3834 #include<cstdio> #include<iostream> #include ...

  8. [ZJOI2019]线段树

    题目大意 一开始有一棵线段树,然后有一个操作序列,问执行这个操作序列的所有子集时线段树上有标记的节点个数和. 题解 其实我们把它除以\(2^m\)后发现就是有标记节点的期望个数. 然后套路的根据期望的 ...

  9. Luogu5280 ZJOI2019线段树(线段树)

    容易发现相当于求2m种操作序列所得的每种线段树tag数量之和.显然考虑每个点的贡献,也即有多少种方案会使该点上有tag.可以将点分为四类: 1.修改时被经过且有儿子被修改的节点 2.修改时被经过且没有 ...

随机推荐

  1. 想晋级高级工程师只知道表面是不够的!Git内部原理介绍

    本文由云+社区发表 作者:腾讯工蜂用户:王二卫 从不一样的视角了解git,以便更好的使用git 一.git & git 版本库认识 git 是一个内容寻址的文件系统,其核心部分是一个简单的键值 ...

  2. linux centos6.5安装KVM

    1.安装kvm,vnc软件 http://www.server110.com/kvm/201404/10467.html yum install kvm,缺啥补啥 yum install kvm km ...

  3. 重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)

    一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用 ...

  4. python基础4--控制流

    1.if语句 结构: if condition: do something elif other_condition: do something number = 60 guess = int(inp ...

  5. 分享几个有趣的Linux命令

    前言 最近工作比较忙,没时间写博客,这次介绍几个有趣的Linux命令. 命令:sl 当你使用这个命令时会看到一辆小火车从你的屏幕经过.亲测! 安装命令如下: yum -y install sl 执行效 ...

  6. Tomcat常用的过滤器

    前言 之前我很肤浅的以为为了实现某种请求过滤功能(比如图片转换.文件上传.安全认证等),都需要自己去实现javax.servlet.Filter.之后在web.xml中配置即可. 但事实上,Tomca ...

  7. C#添加PDF页眉——添加文本、图片到页眉

    页眉常用于显示文档的附加信息,我们可以在页眉中插入文本或者图形,例如,页码.日期.公司徽标.文档标题.文件名或作者名等等.那么我们如何以编程的方式添加页眉呢?今天,这篇文章向大家分享如何使用了免费组件 ...

  8. 学习安卓开发[2] - 在Activity中托管Fragment

    目录 在上一篇学习安卓开发[1]-程序结构.Activity生命周期及页面通信中,学习了Activity的一些基础应用,基于这些知识,可以构建一些简单的APP了,但这还远远不够,本节会学习如何使用Ac ...

  9. 自动给 Asp.Net Core WebApi 增加 ApiVersionNeutral

    自动给 Asp.Net Core WebApi 增加 ApiVersionNeutral Intro 新增加一个 Controller 的时候,经常忘记在 Controller 上增加 ApiVers ...

  10. Jmeter设置代理,抓包之app请求

    步骤: 1. Jmeter选择测试计划,添加线程组,添加http请求,添加监听器-察看结果树 2. 添加http代理服务器,右键添加非测试元件-添加http代理服务器 3. 端口改为8889,目标控制 ...