题目描述
九条可怜是一个喜欢数据结构的女孩子,在常见的数据结构中,可怜最喜欢的就是线段树。
线段树的核心是懒标记,下面是一个带懒标记的线段树的伪代码,其中 数组为懒标记:
其中函数 表示 的左儿子, 表示 的右儿子。
现在可怜手上有一棵 上的线段树,编号为 。这棵线段树上的所有节点的 均为 。接下来可怜进行了 次操作,操作有两种:
,假设可怜当前手上有 棵线段树,可怜会把每棵线段树复制两份( 数组也一起复制),原先编号为 的线段树复制得到的两棵编号为 与 ,在复制结束后,可怜手上一共有 棵线段树。接着,可怜会对所有编号为奇数的线段树进行一次 。
,可怜定义一棵线段树的权值为它上面有多少个节点 为 。可怜想要知道她手上所有线段树的权值和是多少。
输入输出格式
输入格式:
第一行输入两个整数
表示初始区间长度和操作个数。
接下来 行每行描述一个操作,输入保证 。
输出格式:
对于每次询问,输出一行一个整数表示答案,答案可能很大,对
取模后输出即可。
输入输出样例
输入样例#1:
5 5
2
1 1 3
2
1 3 5
2
输出样例#1:
0
1
6
说明
上的线段树如下图所示:
在第一次询问时,可怜手上有一棵线段树,它所有点上都没有标记,因此答案为 。
在第二次询问时,可怜手上有两棵线段树,按照编号,它们的标记情况为:
点
上有标记,权值为
。
没有点有标记,权值为
。
因此答案为
。
在第三次询问时,可怜手上有四棵线段树,按照编号,它们的标记情况为:
点
上有标记,权值为
。
点
上有标记,权值为
。
点
上有标记,权值为
。
没有点有标记,权值为
。
因此答案为
。
分析:
我们把线段树上的点分成5类。
假设操作区间为
,第一类点区间
包含
。也就是线段树操作经过的点,即白色点。
第二类点是修改点,即打上
的点,深灰色点。
第三类点是不直接遍历到,但是可以通过下传改变的点,即橙色点。
第四类点是第二类点的儿子,第五类点是第三类点的儿子。
我们设
表示前
次操作后,
号节点
的个数。
表示第
次操作后,
到根路径上不含
的个数。
对于第一类点,显然所有点
都被清掉,
第二类点都打上了
,
第三类点取决于上面有没有
,
第四类点和第五类点类似,都是影响不到的,只是修改后四类点的
一定是0
其中一二三类点为 个,四五类点为 个。对于四五类点,可以通过线段树打tag的方式,也就是个最浅的儿子打上乘2的tag。
代码:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const int maxn=2e6+7;
const LL mod=998244353;
using namespace std;
int n,m,k,op,x,y;
LL f[maxn],g[maxn],a[maxn],b[maxn],sum[maxn];
void build(int p,int l,int r)
{
g[p]=a[p]=b[p]=1;
if (l==r) return;
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
}
void pushf(int p,LL k)
{
f[p]=f[p]*k%mod;
sum[p]=sum[p]*k%mod;
a[p]=a[p]*k%mod;
}
void pushg(int p,LL k)
{
g[p]=g[p]*k%mod;
b[p]=b[p]*k%mod;
}
void pushdown(int p)
{
if (a[p]!=1)
{
pushf(p*2,a[p]);
pushf(p*2+1,a[p]);
a[p]=1;
}
if (b[p]!=1)
{
pushg(p*2,b[p]);
pushg(p*2+1,b[p]);
b[p]=1;
}
}
void modify(int p,int l,int r,int x,int y)
{
pushdown(p);
if ((l==x) && (r==y))
{
f[p]=(f[p]+(LL)k)%mod;
pushf(p*2,2);
pushf(p*2+1,2);
}
else
{
int mid=(l+r)/2;
g[p]=(g[p]+(LL)k)%mod;
if (y<=mid)
{
modify(p*2,l,mid,x,y);
pushdown(p*2+1);
f[p*2+1]=(f[p*2+1]+(LL)k+mod-g[p*2+1])%mod;
g[p*2+1]=g[p*2+1]*2%mod;
pushf((p*2+1)*2,2),pushf((p*2+1)*2+1,2);
pushg((p*2+1)*2,2),pushg((p*2+1)*2+1,2);
sum[p*2+1]=(sum[(p*2+1)*2]+sum[(p*2+1)*2+1]+f[p*2+1])%mod;
}
else
{
if (x>mid)
{
modify(p*2+1,mid+1,r,x,y);
pushdown(p*2);
f[p*2]=(f[p*2]+(LL)k+mod-g[p*2])%mod;
g[p*2]=g[p*2]*2%mod;
pushf((p*2)*2,2),pushf((p*2)*2+1,2);
pushg((p*2)*2,2),pushg((p*2)*2+1,2);
sum[p*2]=(sum[(p*2)*2]+sum[(p*2)*2+1]+f[p*2])%mod;
}
else
{
modify(p*2,l,mid,x,mid);
modify(p*2+1,mid+1,r,mid+1,y);
}
}
}
sum[p]=(sum[p*2]+sum[p*2+1]+f[p])%mod;
}
int main()
{
scanf("%d%d",&n,&m);
build(1,1,n);
k=1;
for (int i=1;i<=m;i++)
{
scanf("%d",&op);
if (op==1)
{
scanf("%d%d",&x,&y);
modify(1,1,n,x,y);
k=(LL)k*2%mod;
}
else printf("%lld\n",sum[1]);
}
}