首页 > 其他分享 >【ZJOI2019】线段树

【ZJOI2019】线段树

时间:2023-02-20 22:15:04浏览次数:41  
标签:int 线段 add 1ll ZJOI2019 mul mo

【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;
}

标签:int,线段,add,1ll,ZJOI2019,mul,mo
From: https://www.cnblogs.com/AmanoKumiko/p/17139126.html

相关文章

  • hihoCoder 1078 : 线段树的区间修改
    #1078:线段树的区间修改10000ms1000ms256MB描述对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho:假设货架上......
  • 线段树板子C++
    structnode{intl,r,sum,lazy;node*lson,*rson;node(){l=r=sum=lazy=0;lson=rson......
  • 区间和线段树的各种操作
    这篇文章我们来讲一下线段树线段树,适用于对一个数列区间进行操作,可以求这段数列\(i\)到\(j\)的和、乘积、最大值、最小值等等等等,因此线段树有十分多的变种问题提出如......
  • 线段树
    前言线段树经常用来维护区间信息,支持单点修改、区间修改、单点查询、区间查询等操作。其中单点修改/查询其实可以类似地看成区间长度为\(1\)的区间。而上面的操作时间复......
  • 线段树
    权值线段树线段树维护的区间是一个值域范围,而不是一段下标的区间。P1637三元上升子序列我们可以考虑中间的数字\(x\),统计前面比\(x\)小的数字个数\(a_1\),统计后......
  • ACwing 区间最大公约数题解 线段树(附证明)
    算进区间最大公因数单点线段树 https://www.acwing.com/problem/content/247/题目:给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:Clrd,表......
  • 线段树以及其高级用法
    1.线段树2.动态开点及标记永久化3.线段树的分裂和合并4.李超线段树5.zkw线段树6.树套树7.线段树分治8.猫树......
  • Educational Codeforces Round 102 (Rated for Div. 2)D(线段树求贡献)
    EducationalCodeforcesRound102(RatedforDiv.2)D(线段树求贡献)D.Program题目大意:最初x为0,给定一个长度为n的操作序列,共有两种操作:-,x-=1;+,x+=1;有m次询......
  • Codeforces Round #442 (Div. 2)E. Danil and a Part-time Job 线段树+lazytag
    题意:一颗有根树,树上每一个节点有一个灯,要支持两种操作第一种操作是统计一颗子树内开着的灯个数。第二种操作是将一个子树内的所有灯状态改变(开灯->关灯,关灯->开灯)。解......
  • CF1567E Non-Decreasing Dilemma 题解 线段树
    题目链接:http://codeforces.com/problemset/problem/1567/E题目大意:有一个长度为\(n\)的数列\(a\),你需要对其进行\(q\)次操作,操作有两种类型,按如下格式给出:1xy:......