【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;
}
posted @ 2023-02-20 21:58  冰雾  阅读(36)  评论(0编辑  收藏  举报