首页 > 其他分享 >郝玩的数据结构——线段树(待upd)

郝玩的数据结构——线段树(待upd)

时间:2024-11-23 12:12:02浏览次数:6  
标签:lc int upd tr mid push 数据结构 郝玩 线段

线段树,是一种支持点修点查,去修区查的高级数据结构,单词操作时间复杂度为O(log2点数),非常的优秀
拉张图来解释一下线段树:

每个父节点的权值是两个子节点权值的和
好的。首先建一棵线段树我们来采用递归建树:先从根节点DFS遍历,然后返回后使用push_up函数累加——这样就可以保证线段树的性质
其次就是修改
如果是单点修改的话就从根节点向下找到该节点然后返回的时候沿途更新其祖先
如果是区间修改的话
引入:懒标记:LAZYTAG
如果一个个修改的话复杂度很高,所以当修改时应该找到比所选区间小或相等的一个或者几个区间,并使区间的交集为空,并集为所选区间
然后就是查询
单点查询就是从线段树的根走到最末一层,不多说
区间查询
和区修极其神似的,区查就是选几个。。。(上面有)的区间,累加和,作为答案,输出
想必通过我的解释,你一定没懂,啊不,懂了,所以,让我们来看代码——板子题,以及板子题的微调(板子还有个区间乘加,可是老登笔者还没有Ac(没做))

哦对了,线段树码量真多,(当然也有老登笔者菜的原因),但这不是重点

线段树一定要开4倍数组!!!!

点击查看代码
#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define int long long
using namespace std;
inline int read(){
	int nb=0,f=1;
	char c=getchar();
	while(c>'9' || c<'0'){
		if(c=='-'){
			f=-f;
		}
		c=getchar();
	}
	while(c>='0' && c<='9'){
		nb=nb*10+c-'0';
		c=getchar();
	}
	return nb*f;
}
const int N=1e6+145;

struct nb{
	int l,r,sum,tag;
	nb(int a,int b,int c,int d):l(a),r(b),sum(c),tag(d){}
	nb(){}
}tr[N<<2];
int n,q,wq,l,r,x;
int a[N];

inline void push_up(int p){
	tr[p].sum=tr[lc].sum+tr[rc].sum;
}

inline void push_down(int p){
	if(tr[p].tag){
		tr[lc].tag+=tr[p].tag;
		tr[rc].tag+=tr[p].tag;
		tr[lc].sum+=tr[p].tag*(tr[lc].r-tr[lc].l+1);
		tr[rc].sum+=tr[p].tag*(tr[rc].r-tr[rc].l+1);
		tr[p].tag=0;
	}
}

inline void bt(int p,int l,int r){//buildtree
	tr[p]={l,r,a[l],0};
	if(l==r){
		return ;
	}
	int mid=(l+r)>>1;
	bt(lc,l,mid);
	bt(rc,mid+1,r);
	push_up(p);
}

inline void wlgd(int p,int l,int r,int k){
	if(tr[p].l>=l && tr[p].r<=r){
		tr[p].tag+=k;
		tr[p].sum+=k*(tr[p].r-tr[p].l+1);
		return ;
	}
	int mid=tr[p].l+tr[p].r>>1;
	push_down(p);
	if(mid>=l) wlgd(lc,l,r,k);
	if(mid<r) wlgd(rc,l,r,k);
	push_up(p);
}

inline int query(int p,int l,int r){
	if(l<=tr[p].l && r>=tr[p].r){
		return tr[p].sum;
	}
	int res=0;
	int mid=tr[p].l+tr[p].r>>1;
	push_down(p);
	if(mid>=l) res+=query(lc,l,r);
	if(mid<r) res+=query(rc,l,r);
	return res;
}
signed main(){
	n=read(),q=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
	}
	bt(1,1,n);
//	for(int i=1;i<=2*n;i++){
//		cout<<tr[i].sum<<"  ";
//	}
	for(int i=1;i<=q;i++){
		cin>>wq;
		if(wq==1){
			l=read(),r=read(),x=read();
		//cin>>l>>r>>x;
			wlgd(1,l,r,x);
		}
		else{
			l=read(),r=read();
			//cin>>l>>r;
			cout<<query(1,l,r)<<"\n";
		}
	}
	return 0;
}

板子题1

点击查看代码
#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define int long long
using namespace std;
int n,m,op,ll,rr;
const int N=2e5+10;
char c[N];
struct node{
	int sum,tag,l,r;
}tr[N<<2];

void push_up(int p){
	tr[p].sum=tr[lc].sum+tr[rc].sum;
}

void push_down(int p){
	if(tr[p].tag){
		tr[lc].tag^=1;
		tr[rc].tag^=1;
		tr[lc].sum=tr[lc].r-tr[lc].l+1-tr[lc].sum;
		tr[rc].sum=tr[rc].r-tr[rc].l+1-tr[rc].sum;
		tr[p].tag=0;
	}
}

void buildtree(int p,int l,int r){
	tr[p]={0,0,l,r};
	if(l==r){
		if(c[l]=='1'){
			tr[p].sum++;
		}
		return ;
	}
	int mid=l+r>>1;
	buildtree(lc,l,mid);
	buildtree(rc,mid+1,r);
	push_up(p);
}

void update(int p,int l,int r){
	if(tr[p].l>=l && tr[p].r<=r){
		tr[p].tag^=1;
		tr[p].sum=tr[p].r-tr[p].l+1-tr[p].sum;
		return ;
	}
	int mid=tr[p].l+tr[p].r>>1;
	push_down(p);
	if(mid>=l) update(lc,l,r);
	if(mid<r) update(rc,l,r);
	push_up(p);
}

int query(int p,int l,int r){
	int res=0;
	if(tr[p].l>=l && tr[p].r<=r){
		return tr[p].sum;
	}
	push_down(p);
	int mid=tr[p].l+tr[p].r>>1;
	if(mid>=l) res+=query(lc,l,r);
	if(mid<r) res+=query(rc,l,r);
	return res;
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>c[i];
	}
	buildtree(1,1,n);
	for(int i=1;i<=m;i++){
		cin>>op>>ll>>rr;
		if(op==0){
			update(1,ll,rr);
		}
		else{
			cout<<query(1,ll,rr)<<"\n";
		}
	}
	return 0;
}

一点小进阶

好的,哪天闲的没事再来更个点修点查啥的
不过想必聪明的你会了区修区查之后一定也会点修点查了
拜拜~

标签:lc,int,upd,tr,mid,push,数据结构,郝玩,线段
From: https://www.cnblogs.com/cathyzro/p/18564300

相关文章

  • 分段回归:处理数据结构性变化的有力工具
    分段回归:处理数据结构性变化的有力工具一、引言1.1问题背景现实数据中的结构性变化政策影响导致的突变自然现象的阈值效应经济周期的转折点传统线性回归的局限性无法捕捉数据的突变点对结构性变化敏感可能导致严重的拟合偏差1.2算法概述分段回......
  • C语言数据结构与算法--简单实现栈的出栈与入栈
     目录(一)栈的基本概念(二)栈的的表现形式1.栈的表示和实现2.栈的链式表示(三)栈的链式表示时元素压入、弹出 算法实现思路1.栈的线性链表的压入算法2.栈的线性链表的弹出算法(四)算法的实现(一)栈的基本概念        栈(Stack)是限定仅在表尾进行插入和删除操作的线......
  • 【数据结构】哈夫曼树的构建和哈夫曼编码
    说明本篇为笔者学习随记,供学习和复习使用结构体定义typedefstruct{ intweight=0; intparent=0,lchild=0,rchild=0;}HTNode;此处=0可使结构体在构建时就自动初始化typedefchar**HuffmanCode;把多重指针换成HuffmanCode 哈夫曼树的构建构建思路:a)初始化哈夫......
  • 数据结构与算法——树与二叉树
    树与二叉树1.树的定义与相关概念树的示例:树的集合形式定义Tree=(K,R)元素集合:K={ki|0<=i<=n,n>=0,ki∈ElemType}(n为树中结点数,n=0则树为空,n>0则为非空树)对于一棵非空树,关系R满足下列条件:1.有且仅有一个结点没有前驱,称为根结点。2.处根结点外,其余每个结点有且仅有一个前......
  • 数据结构:(OJ917)仅仅反转字母
    给你一个字符串 s ,根据下述规则反转字符串:所有非英文字母保留在原有位置。所有英文字母(小写或大写)位置反转。返回反转后的 s 。示例1:输入:s="ab-cd"输出:"dc-ba"示例2:输入:s="a-bC-dEf-ghIj"输出:"j-Ih-gfE-dCba"示例3:输入:s="Test1ng-Leet=code-Q!"输出:"......
  • 数据结构与算法——顺序栈的实现
    数据结构栈——一列数据,表尾入栈,表尾出栈,类似于子弹弹匣,压入子弹和拿出子弹都是从最上方进出。结构体structStack{ int*arr; intcapacity;//数组容量 inttop;//存储栈顶元素的下标};初始化栈intInitStack(structStack*stack){ stack->arr=......
  • 初阶数据结构【3】--单链表(比顺序表还好的一种数据结构!!!)
    本章概述前情回顾单链表实现单链表彩蛋时刻!!!前情回顾咱们在上一章博客点击:《顺序表》的末尾,提出了一个问题,讲出了顺序表的缺点——有点浪费空间。所以,为了解决这个问题,我们今天就要讲解链表,咱们在讲结构体的时候有提到过链表,链表的最大优点——一点空间也不浪费,用多少......
  • [数据结构] 删除单链表中最小值结点(C语言版本)
    如果对单链表基本操作或概念不理解的可以跳转:单链表的基本操作(C语言版)-CSDN博客https://blog.csdn.net/m0_74181956/article/details/143082621?spm=1001.2014.3001.5501算法思想:如图所示:定义指针p为L的第一个结点,pre为L的头结点,min为记录每次遍历的最小值结点,minpre为记......
  • 【趣学C语言和数据结构100例】
    #1024程序员节|征文#【趣学C语言和数据结构100例】问题描述56.设将n(n>1)个整数存放到区带头结点处单链表乚中,设计算法将L中保存的序列循环石移k(0<k<n)个位置。例如,若k=1,则将链表(0,1,2,3}变为{3,0,1,2}57.设有一个带头结点的非循环双链表L,其每个结点中除有pre、da......
  • 数据结构 链表 C语言
    数据结构第二章的链表//线性表的链式存储#include<stdlib.h>#include<stdio.h>typedefintElemType;typedefstructnode{ElemTypedata;structnode*next;}Node,*LinkList;//初始化空的单链表voidInitList(LinkList*L){*L=(LinkLis......