首页 > 其他分享 >刍议线段树 2 (区间修改,区间查询)

刍议线段树 2 (区间修改,区间查询)

时间:2024-08-09 20:55:28浏览次数:10  
标签:int 线段 刍议 cin 查询 tag 区间

线段树 \(2\)

接上一讲

https://www.cnblogs.com/yingxilin/p/18350988
(没看的同学们可以先看这篇)

上一讲里我们已经介绍了单点修改,区间查询的线段树了。
在这一讲里,我们开始学习支持区间修改,区间查询的线段树。
考虑之前的做法,之前的查询区间会被分为 \(O(logn)\),从而求解,但因为所有子树节点要一起更新, 复杂度沦为 \(O(n)\) ,无法接受。

tag-懒惰标记

这时,我们可以给要修改的点加一个懒惰标记 \(tag\) ,标记为“该点已经被修改,其子节点尚未被更新”,再将其下传。之后在递归进入其父节点时再判断其是否带有 \(tag\) 标记,若有,再将其更新。如此一来,就不用修改一个点时更新所有子树节点,只需要把要用到的节点更新,大大减小了算法复杂度。具体操作看代码,有注释。

区间更改,区间查询

例题:
https://www.luogu.com.cn/problem/P3372

大意:区间加,区间求和

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define FOR(i,_l,_r) for(int i=_l;i<=_r;i++)
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)//这里一定要记得打上括号,不然会调得很惨
#define len(x) (t[x].r-t[x].l+1)
const int N=1e5+5;
struct Node{
	int l,r;//左右儿子
	int sum,tag;//区间和,懒惰标记
}t[N<<2];
int a[N];
int n,m;
void up(int p){//向上更新
	t[p].sum=t[ls].sum+t[rs].sum;
}
void build(int p,int l,int r){//建树
	t[p].l=l;t[p].r=r;
	if(l==r){
		t[p].sum=a[l];
		return;
	}
	build(ls,l,mid);
	build(rs,mid+1,r);
	up(p);
}

void down(int p){//懒惰标记下放
	if(!t[p].tag) return;//无tag,return;
	int k=t[p].tag;
	t[ls].sum+=k*len(ls);//更新左区间
	t[rs].sum+=k*len(rs);//更新右区间
	t[ls].tag+=k;//传给左儿子
	t[rs].tag+=k;//传给右儿子
	t[p].tag=0;//记得把当前标记清零
}

void change(int p,int L,int R,int v){//修改
	int l=t[p].l;
	int r=t[p].r;
	if(L<=l&&r<=R){
		t[p].sum+=v*len(p);//更新当前节点的区间和
		t[p].tag+=v;//更新tag
		return;
	}
	down(p);//下放
	if(L<=mid) change(ls,L,R,v);
	if(R>mid) change(rs,L,R,v);
	up(p);
}

int query(int p,int L,int R){//查询
	int l=t[p].l;
	int r=t[p].r;
	if(L<=l&&r<=R)  return t[p].sum;
	down(p);//下放
	int ans=0;
	if(L<=mid) ans+=query(ls,L,R);
	if(R>mid) ans+=query(rs,L,R);
	return ans;
}

signed main(){
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	// ios::sync_with_stdio(false);
	// cin.tie(NULL);
	cin>>n>>m;
	FOR(i,1,n)  cin>>a[i];
	build(1,1,n);//建树
	while(m--){
		// cout<<1;
		int opt,x,y,k;
		cin>>opt>>x>>y;
		if(opt==1){
			cin>>k;
			change(1,x,y,k);
		}
		else  cout<<query(1,x,y)<<endl;
	}
	return 0;
}

标签:int,线段,刍议,cin,查询,tag,区间
From: https://www.cnblogs.com/yingxilin/p/18351492

相关文章

  • 线段树维护区间方差
    线段树维护区间方差方差区间方差还教室解题思路:利用线段树维护\(a_i\)与\(a_i^2\)\((1\leqi\leqn)\)两个数列,然后使用一个\(lazytag\)来记录是否进行了区间加,最后输出方差的时候使用$$s^2=\sum\limits_{i=1}^n(a_i-\overlinea)^2=(\sum\limits_{i=1}......
  • 洛谷 P3870 开关之线段树板子
    洛谷P3870题解传送锚点摸鱼环节[TJOI2009]开关题目描述现有\(n\)盏灯排成一排,从左到右依次编号为:\(1\),\(2\),……,\(n\)。然后依次执行\(m\)项操作。操作分为两种:指定一个区间\([a,b]\),然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开);指定一个区间......
  • 8.9 线段树板子+三分补题+三维的bfs
    nowcoder训练区间线段树板子题,我们只需要把区间每一个点设置成1,然后修改的时候直接改点,然后查区间就行线段树维护最大字段和/01串最大连续1的个数模板题。把白色和黑色看成1/0两个数就行了。#include<bits/stdc++.h>usingnamespacestd;usingi64=longlon......
  • 【线段树合并/树上差分】[P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并
    【线段树合并/树上差分】P4556[Vani有约会]雨天的尾巴/【模板】线段树合并思路对\(x,y,lca(u,v),fa_{lca(u,v)}\)四个点进行树上差分,然后用线段树合并动态权值线段树。#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;template<classNode>str......
  • 线段树合并模板
    template<classNode>structPersidentSegmentTree{#definelc(u)tr[u].l#definerc(u)tr[u].rconstintn;inttot=0;vector<Node>tr;vector<int>root;PersidentSegmentTree():n(0){}PersidentSegmentTree(in......
  • 【题解】Solution Set - NOIP2024集训Day2 线段树
    【题解】SolutionSet-NOIP2024集训Day2线段树https://www.becoder.com.cn/contest/5431「CF1149C」TreeGenerator™结论:对于括号序列的一个子段,删去所有的匹配括号之后,剩下的不匹配的括号,按顺序构成树上的一条路径。Why?从括号序列的构造出发。每次(相当于开始遍历......
  • P3834 【模板】可持久化线段树 2
    P3834【模板】可持久化线段树2-洛谷|计算机科学教育新生态(luogu.com.cn)#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;template<classNode>structPersidentSegmentTree{#definelc(u)tr[u].l#definerc(u)tr[u].r#definesum(u)t......
  • 洛谷P3842 线段——题解
    洛谷P3842题解传送锚点摸鱼环节[TJOI2007]线段题目描述在一个\(n\timesn\)的平面上,在每一行中有一条线段,第\(i\)行的线段的左端点是\((i,L_{i})\),右端点是\((i,R_{i})\)。你从\((1,1)\)点出发,要求沿途走过所有的线段,最终到达\((n,n)\)点,且所走的路程长度要尽......
  • DAY6 位运算、离散化、区间和并
    本文所有题目都可在acwing题库中找到,本文仅进行归纳整理题目:acwing801给定一个长度为 n的数列,请你求出数列中每个数的二进制表示中 1的个数。输入格式第一行包含整数 n。第二行包含 n个整数,表示整个数列。输出格式共一行,包含 n个整数,其中的第 i个数表示数列中的第......
  • 刍议树状数组
    树状数组用处区间加,单点查询单点加,区间查询区间加,区间查询求逆序对……思想树状数组的思想对于线段树等结构来说比较抽象,所以我也懒得讲……在这我只讲一下我对于树组的理解,对于实战来说完全够用。先讲一个叫\(lowbit\)的东西,求一个数二进制下最后一个\(1\)的位置,比......