【ZJOI2019】线段树
【ZJOI2019】线段树
Description
九条可怜是一个喜欢数据结构的女孩子,在常见的数据结构中,可怜最喜欢的就是线段树。
线段树的核心是懒标记,下面是一个带懒标记的线段树的伪代码,其中 \(tag\) 数组为懒标记:
其中函数 \(\operatorname{Lson}(Node)\) 表示 \(Node\) 的左儿子,\(\operatorname{Rson}(Node)\) 表示 \(Node\) 的右儿子。
现在可怜手上有一棵 \([1,n]\) 上的线段树,编号为 \(1\)。这棵线段树上的所有节点的 \(tag\) 均为\(0\)。接下来可怜进行了 \(m\) 次操作,操作有两种:
-
\(1\ l\ r\),假设可怜当前手上有 \(t\) 棵线段树,可怜会把每棵线段树复制两份(\(tag\) 数组也一起复制),原先编号为 \(i\) 的线段树复制得到的两棵编号为 \(2i-1\) 与 \(2i\),在复制结束后,可怜手上一共有 \(2t\) 棵线段树。接着,可怜会对所有编号为奇数的线段树进行一次 \(\operatorname{Modify}(root,1,n,l,r)\)。
-
\(2\),可怜定义一棵线段树的权值为它上面有多少个节点 \(tag\) 为 \(1\)。可怜想要知道她手上所有线段树的权值和是多少。
Input
第一行输入两个整数 \(n,m\) 表示初始区间长度和操作个数。
接下来 \(m\) 行每行描述一个操作,输入保证 \(1 \le l \le r \le n\)。
Output
对于每次询问,输出一行一个整数表示答案,答案可能很大,对 \(998244353\) 取模后输出即可。
Sample Input
5 5
2
1 1 3
2
1 3 5
2
Sample Output
0
1
6
Data Constraint
\(1\le n,m\le10^5\)
Solution
对于分类讨论的题目还是有很多思维漏洞啊
每个点维护两个值,
一个为有标记的概率,记为\(f\),
一个为这个点到根至少有一个点有标记的概率,记作\(g\)
然后对每一组父子节点考虑
1.当前区间和父区间无交
显然标记不变
2.当前区间和父区间有交,和子区间无交
那么这个点只和其自身是否有标记,以及到根的链是否有标记有关
3.当前区间完全覆盖子区间,但没完全覆盖父区间
那么这个点一定有标记
4.当前区间完全覆盖父区间
显然这个点标记不变
5.当前区间和子区间有交
那么这个点一定会进行pushdown
每类点都可以在线段树上简单维护,复杂度1log
Code
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define mo 998244353
#define N 100010
#define ls x<<1
#define rs (x<<1)|1
int mod(int x){return x>=mo?x-mo:x;}
int mi(int x,int y){
int res=1;
for(;y;x=1ll*x*x%mo,y>>=1)if(y&1)res=1ll*res*x%mo;
return res;
}
const int i2=mi(2,mo-2);
int n,m;
struct tree{
int f[N*8],g[N*8],s[N*8];
int mul[N*8],add[N*8];
void pushup(int x){s[x]=mod(mod(s[ls]+s[rs])+f[x]);}
void update(int x){
f[x]=1ll*i2*mod(f[x]+g[x])%mo;
pushup(x);
}
void pushdown(int x){
if(mul[x]==1&&add[x]==0)return;
// 1.mul 2.add
mul[ls]=1ll*mul[ls]*mul[x]%mo;
add[ls]=mod(1ll*add[ls]*mul[x]%mo+add[x]);
g[ls]=mod(1ll*g[ls]*mul[x]%mo+add[x]);
mul[rs]=1ll*mul[rs]*mul[x]%mo;
add[rs]=mod(1ll*add[rs]*mul[x]%mo+add[x]);
g[rs]=mod(1ll*g[rs]*mul[x]%mo+add[x]);
mul[x]=1;add[x]=0;
}
void modify(int x,int l,int r,int ll,int rr){
if(l==ll&&r==rr){
// 3
f[x]=1ll*i2*mod(f[x]+1)%mo;
g[x]=1ll*i2*mod(g[x]+1)%mo;
// 4
mul[x]=1ll*mul[x]*i2%mo;
add[x]=mod(1ll*add[x]*i2%mo+i2);
pushup(x);
return;
}
int mid=l+r>>1;
pushdown(x);
// 5
f[x]=1ll*i2*f[x]%mo;
g[x]=1ll*i2*g[x]%mo;
// 2
if(ll>=mid+1){
modify(rs,mid+1,r,ll,rr);
update(ls);
}else
if(rr<=mid){
modify(ls,l,mid,ll,rr);
update(rs);
}else{
modify(ls,l,mid,ll,mid);
modify(rs,mid+1,r,mid+1,rr);
}
pushup(x);
}
void build(){F(i,1,n*8)mul[i]=1;}
}t;
int pw=1;
int main(){
scanf("%d%d",&n,&m);
t.build();
F(i,1,m){
int op,l,r;
scanf("%d",&op);
if(op==1){
scanf("%d%d",&l,&r);
t.modify(1,1,n,l,r);
pw=mod(pw+pw);
}else printf("%d\n",1ll*t.s[1]*pw%mo);
}
return 0;
}