送我退役的神题,但不得不说是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

#include<cstdio>
#include<cctype>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=100005,mod=998244353,inv2=499122177;
int n,m,opt,x,y,ipw[N],ret,prod;
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x)
{
if (!x) return (void)(pc('0'),pc('\n')); RI ptop=0;
while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n');
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
#undef tc
#undef pc
}F;
inline void inc(int& x,CI y)
{
if ((x+=y)>=mod) x-=mod;
}
inline void dec(int& x,CI y)
{
if ((x-=y)<0) x+=mod;
}
inline int sum(CI x,CI y)
{
int t=x+y; return t>=mod?t-mod:t;
}
inline int sub(CI x,CI y)
{
int t=x-y; return t<0?t+mod:t;
}
class Segment_Tree
{
private:
struct segment
{
int f,g,tag;
}node[N<<2];
#define F(x) node[x].f
#define G(x) node[x].g
#define T(x) node[x].tag
inline void pushdown(CI now)
{
if (!T(now)) return; int& add=T(now); T(now<<1)+=add; T(now<<1|1)+=add;
G(now<<1)=sum(1LL*G(now<<1)*ipw[add]%mod,sub(1,ipw[add]));
G(now<<1|1)=sum(1LL*G(now<<1|1)*ipw[add]%mod,sub(1,ipw[add])); add=0;
}
public:
inline void modify(CI beg,CI end,CI now=1,CI l=1,CI r=n)
{
dec(ret,F(now)); F(now)=1LL*F(now)*inv2%mod; G(now)=1LL*G(now)*inv2%mod;
if (beg<=l&&r<=end) inc(F(now),inv2),inc(G(now),inv2);
if (l>end||r<beg) inc(F(now),G(now)),inc(G(now),G(now)); inc(ret,F(now));
if (l>end||r<beg) return; if (beg<=l&&r<=end) return (void)(++T(now));
pushdown(now); int mid=l+r>>1; modify(beg,end,now<<1,l,mid); modify(beg,end,now<<1|1,mid+1,r);
}
#undef F
#undef G
#undef T
}SEG;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),F.read(m),ipw[0]=i=1;i<=m;++i)
ipw[i]=1LL*ipw[i-1]*inv2%mod; for (i=prod=1;i<=m;++i)
{
F.read(opt); if (opt^1) F.write(1LL*ret*prod%mod);
else inc(prod,prod),F.read(x),F.read(y),SEG.modify(x,y);
}
return F.Fend(),0;
}

最新文章

  1. SSH遇见的问题
  2. 第二篇、微信程序尺寸rpx
  3. IOS中的内存不足警告处理(译)
  4. 关于 Boolean 的转换
  5. [ An Ac a Day ^_^ ] HDU 1257 基础dp 最长上升子序列
  6. Java中字符串indexof() 的使用方法
  7. 小强的HTML5移动开发之路(19)——HTML5 Local Storage(本地存储)
  8. python中字符串拆分与合并——split()、join()、strip()和replace()
  9. 安装Cnario提示.Net 3.5安装错误, 检查Windows系统更新提示无法检查到更新, 安装.Net 3.5提示&quot;Windows无法完成请求的更改, 错误代码:0x800F081F&quot;
  10. Android Studio Termanal打不开,提示java.io.IOEXception:couldn&#39;t create PTY
  11. [PHP]算法-二进制中1的个数的PHP实现
  12. 网络流24(san)题题解汇总
  13. C#_02.16_基础七_.NET表达式&amp;运算符
  14. 关于python中pika模块的问题
  15. SQL调优日记--并行等待的原理和问题排查
  16. RabbitMQ随笔
  17. Spring、Springmvc整合web的web.xml配置
  18. linux RPM包安装、更新、删除等操作命令简明总结, 如何查看yum安装的软件路径 ?
  19. eclipse再见,android studio 新手新手教程(一)基本设置
  20. 为什么c++中,有时可以用类名直接访问非静态成员函数?

热门文章

  1. 看看.NET Core几个Options的简单使用
  2. Jenkins持续集成01—Jenkins服务搭建和部署
  3. .NET WebAPI 利用特性捕捉异常
  4. JQuery官方学习资料(译):CSS
  5. Java基础:Object类中的equals与hashCode方法
  6. Spring笔记04_AOP注解开发_模板_事务
  7. #WEB安全基础 : HTML/CSS | 0x6嵌套标签(图片链接)
  8. My MES思路图
  9. arcgis for js开发之路径分析
  10. C#获得指定目录床架时间、更新时间和最后访问时间等信息的代码