线段树简介

本文详细介绍了线段树这种数据结构,用于高效解决区间查询和修改问题。提供了线段树的C++实现模板,包括区间和、区间修改、单点查询和修改等功能,并通过示例展示了其在区间加值、区间改值、单点查询和修改等操作中的应用。此外,还附带了线段树的B站讲解链接和代码示例,帮助读者深入理解线段树的工作原理。
摘要由CSDN通过智能技术生成

第三天
线段树主要用于解决求区间和、区间修改、区间最值的问题。

线段树模板

#include<bits/stdc++.h>
using namespace std;
 
struct node
{
    int l,r,w,lazy;//tree的l,r表示数组区间[l,r],w表示[l,r]区间和 
}tree[400001];
 
//lazy!=0是加值,lazy!=-1是改值 
 
void build(int v,int l,int r)//建树,v表示tree里第v个结点,tree是完全二叉树 
{
    tree[v].l=l;
	tree[v].r=r;
    if(tree[v].l==tree[v].r)
    {
        scanf("%d",&tree[v].w); 
        return;
    }
    int mid=(l+r)/2;
    build(v*2,l,mid);
    build(v*2+1,mid+1,r);
    tree[v].w=tree[v*2].w+tree[v*2+1].w;
}
 
void downadd(int v)//区间加值lazy=0 标记下传
{
    tree[v*2].lazy+=tree[v].lazy;
    tree[v*2+1].lazy+=tree[v].lazy;
    tree[v*2].w+=tree[v].lazy*(tree[v*2].r-tree[v*2].l+1);
    tree[v*2+1].w+=tree[v].lazy*(tree[v*2+1].r-tree[v*2+1].l+1);
    tree[v].lazy=0;
}
 
void downupdate(int v)//区间改值lazy=-1 标记下传 
{
    tree[v*2].lazy=tree[v].lazy;
    tree[v*2+1].lazy=tree[v].lazy;
    tree[v*2].w=tree[v].lazy*(tree[v*2].r-tree[v*2].l+1);
    tree[v*2+1].w=tree[v].lazy*(tree[v*2+1].r-tree[v*2+1].l+1);
    tree[v].lazy=-1;
}
 
 
int ask_point(int v,int x)//单点查询
{
    if(tree[v].l==tree[v].r)
    {
        return tree[v].w;
    }
    
    if(tree[v].lazy!=0) downadd(v);
    //if(tree[v].lazy!=-1) downupdate(v);//区间改值用-1 
    
    int mid=(tree[v].l+tree[v].r)/2;
    if(x<=mid) ask_point(v*2,x);
    else ask_point(v*2+1,x);
}
 
void change_point(int v,int x,int y)//单点修改,a[x]改为y(或加减等操作) 
{
    if(tree[v].l==tree[v].r)
    {
        //tree[k].w+=y;
        tree[v].w=y; //找到了x这个点,a[x]=y,也可进行其他操作 
        return;
    }
    if(tree[v].lazy!=0) downadd(v);
    //if(tree[v].lazy!=-1) downupdate(v);//区间改值用-1 
    
    int mid=(tree[v].l+tree[v].r)/2;
    if(x<=mid) change_point(v*2,x,y);
    else change_point(v*2+1,x,y);
    
    tree[v].w=tree[v*2].w+tree[v*2+1].w; 
}
 
int ask_interval(int v,int a,int b)//区间查询[a,b]
{
    if(tree[v].l>=a&&tree[v].r<=b) 
    {
        return tree[v].w;
    }
    
    if(tree[v].lazy!=0) downadd(v);
    //if(tree[v].lazy!=-1) downupdate(v);//区间改值用-1 
    
    int sum=0;
    int mid=(tree[v].l+tree[v].r)/2;
    if(a<=mid) sum+=ask_interval(v*2,a,b);
    if(b>mid) sum+=ask_interval(v*2+1,a,b);
    
    return sum;
}
 
void changeadd_interval(int v,int a,int b,int y)//区间加值,[a,b]内所有数同时+y 
{
    if(tree[v].l>=a&&tree[v].r<=b)
    {
        tree[v].w+=(tree[v].r-tree[v].l+1)*y;
        tree[v].lazy+=y;
        return;
    }
    if(tree[v].lazy!=0) downadd(v);
    //if(tree[v].lazy!=-1) downupdate(v);//区间改值用-1 
    
    int mid=(tree[v].l+tree[v].r)/2;
    if(a<=mid) changeadd_interval(v*2,a,b,y);
    if(b>mid) changeadd_interval(v*2+1,a,b,y);
    
    tree[v].w=tree[v*2].w+tree[v*2+1].w;
}
 
void changeupdate_interval(int v,int a,int b,int y)//区间改值,[a,b]内所有数同时修改为y 
{
    if(tree[v].l>=a&&tree[v].r<=b)
    {
        tree[v].w=(tree[v].r-tree[v].l+1)*y;
        tree[v].lazy=y;
        return;
    }
    if(tree[v].lazy!=0) downadd(v);
    //if(tree[v].lazy!=-1) downupdate(v);//区间改值用-1 
    
    int mid=(tree[v].l+tree[v].r)/2;
    if(a<=mid) changeupdate_interval(v*2,a,b,y);
    if(b>mid) changeupdate_interval(v*2+1,a,b,y);
    
    tree[v].w=tree[v*2].w+tree[v*2+1].w;
}
 
int main()
{
	int t,n,m;
	scanf("%d",&t);
	while(t--)
	{
		memset(tree,0,sizeof(tree));//除改值其他操作用0 
		//memset(tree,-1,sizeof(tree));//区间改值用-1 
		scanf("%d",&n);//n个节点 
	    build(1,1,n);//建树 
	    scanf("%d",&m);//m种操作 
	    for(int i=1;i<=m;i++)
	    {
	    	int p,x,y,a,b;
	        scanf("%d",&p);
	        if(p==1)
	        {
	        	printf("**************单点查询操作**************\n");
	            scanf("%d",&x);
	            printf("%d\n",ask_point(1,x));//单点查询,输出第x个数 
	        } 
	        else if(p==2)
	        {
				printf("**************单点修改操作**************\n");
	            scanf("%d%d",&x,&y);
	            change_point(1,x,y);//单点修改 
	        }
	        else if(p==3)
	        {
	        	printf("**************区间查询操作**************\n");
	            scanf("%d%d\n",&a,&b);//区间查询 
	            printf("%d\n",ask_interval(1,a,b));//从第1个结点开始查[a,b]区间 
	        }
	        else if(p==4)
	        {
	        	printf("**************区间加值操作**************\n");
	            scanf("%d%d%d",&a,&b,&y);//区间加值,[a,b]都加上y 
	            changeadd_interval(1,a,b,y);
	        }
	        else
	        {
	        	printf("**************区间改值操作**************");
	        	scanf("%d%d%d",&a,&b,&y);//区间改制,[a,b]的值都改为y
				changeupdate_interval(1,a,b,y);
			}
	    }
	}
    return 0;
}

B站线段树的讲解

线段树图示:
在这里插入图片描述

在这里插入图片描述

#include<stdio.h>
 
#define MAX_LEN 1000//开顶点数量n的四倍大小
 
void build_tree(int arr[],int tree[],int node,int start,int end)//建树 
{
	if(start==end)//递归出口设置好 
	{
		tree[node]=arr[start];//arr[end]
	}
	else
	{
		int mid=(start+end)/2;
		int left_node =2*node+1;
		int right_node=2*node+2;
		
		build_tree(arr,tree,left_node,start,mid);
		build_tree(arr,tree,right_node,mid+1,end);
		tree[node]=tree[left_node]+tree[right_node];
	}
}
 
void update_tree(int arr[],int tree[],int node,int start,int end,int idx,int val)//单点更新:将arr[idx]的值更新为val 
{
	if(start==end)//递归出口设置好 
	{
		arr[idx]=val;//数组真实值 
		tree[node]=val;//建立的线段树上的值 
	}
	else
	{
		int mid=(start+end)/2;
		int left_node =2*node+1;
		int right_node=2*node+2;
		if(idx>=start&&idx<=mid)
		{
			update_tree(arr,tree,left_node,start,mid,idx,val);
		}
		else
		{
			update_tree(arr,tree,right_node,mid+1,end,idx,val);
		}
		tree[node]=tree[left_node]+tree[right_node];
	}
}
 
int query_tree(int arr[],int tree[],int node,int start,int end,int L,int R)//区间查询:查询arr[L]到arr[R]的区间和 
{
	/*
	printf("start = %d\n",start);
	printf("end   = %d\n",end);
	printf("\n");
	*/ 
	
	if(R<start||L>end)//递归出口设置好 
	{
		return 0;
	}
	else if(L<=start&&end>=R)//注意这个出口 
	{
		return tree[node];
	}
	else if(start==end)
	{
		return tree[node];
	}
	else
	{
		int mid=(start+end)/2;
		int left_node =2*node+1;
		int right_node=2*node+2;
		int sum_left=query_tree(arr,tree,left_node,start,mid,L,R);
		int sum_right=query_tree(arr,tree,right_node,mid+1,end,L,R);
		return sum_left+sum_right;
	}
}
 
int main()
{
	int arr[]={1,3,5,7,9,11}; 
	int size=6;
	int tree[MAX_LEN]={0};//存线段树 不要忘记清零,把虚点设为0补为完全二叉树 
	
	build_tree(arr,tree,0,0,size-1);
	for(int i=0;i<15;i++)//查看树中的点 
	{
		printf("tree[%d]===%d\n",i,tree[i]);
	}
	printf("\n");
 
	
	printf("***********************\n");
 
 
	update_tree(arr,tree,0,0,size-1,4,6);
	for(int i=0;i<15;i++)//查看树中的点 
	{
		printf("tree[%d]===%d\n",i,tree[i]);
	}
	printf("\n");
 
 
	printf("***********************\n");
	
 
	int s=query_tree(arr,tree,0,0,size-1,2,5);
	printf("s===%d\n",s);	//输出查询的区间和 
	
	
	printf("***********************\n");
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值