【ACWing】245. 你能回答这些问题吗(线段树)

本文介绍了如何运用线段树解决一个包含5e5数据的区间最大连续子段和问题。关键在于维护从左往右和从右往左的最大和,以确定中间部分的最值。代码中展示了线段树的建树、更新、查询过程,并给出了完整的C++实现。

原题链接

题目:

在这里插入图片描述

输入输出样例:

在这里插入图片描述

解题思路:

单点修改和区间查询问题,而且数据是 5 e 5 5e^5 5e5 的,很自然想到了用线段树来维护。
区 间 最 大 连 续 子 段 和 = m a x ( 左 子 树 的 最 大 连 续 子 段 和 , 右 子 树 的 最 大 连 续 子 段 和 ) 区间最大连续子段和=max(左子树的最大连续子段和,右子树的最大连续子段和) =max()???这样想的话,那么遗漏了一种情况:左端点在左子树,右端点在右子树。所以,最终父节点的答案是左子树,右子树,中间,三者之间最大值。
那么怎么解决中间的情况呢?题目要求是子段是连续的,所以可以维护一个区间从左往右最大和 l m a x lmax lmax ,从右往左最大和 r m a x rmax rmax 。那么中间的值是不是就等于,左子树的 r m a x rmax rmax + 右子树的 l m a x lmax lmax
其他的建树,更新,修改,查询,就都是常规操作了。

代码:

#include <bits/stdc++.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
using namespace std;
const int MAXN = 5e5 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int a[MAXN],n,m;

struct SegTree
{
	int l,r,data;//区间左端点  区间右端点  区间最大连续字段和  
	int sum,lmax,rmax;//区间和  区间最大前缀和  区间最大后缀和 
}tree[MAXN*4];

void pushup(int rt)
{
	tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
	tree[rt].lmax=max(tree[rt<<1].lmax,tree[rt<<1].sum+tree[rt<<1|1].lmax);
	tree[rt].rmax=max(tree[rt<<1|1].rmax,tree[rt<<1|1].sum+tree[rt<<1].rmax);
	tree[rt].data=max(max(tree[rt<<1].data,tree[rt<<1|1].data),tree[rt<<1].rmax+tree[rt<<1|1].lmax);//三者取max 
}

void build(int rt,int l,int r)
{
	tree[rt].l=l;
	tree[rt].r=r;
	if(l==r)
	{
		tree[rt].data=tree[rt].sum=tree[rt].rmax=tree[rt].lmax=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}

void update(int rt,int x,int v)//将第x个的值改为v 
{
	if(tree[rt].l==tree[rt].r)
	{
		tree[rt].data=tree[rt].sum=tree[rt].rmax=tree[rt].lmax=v;
		return; 
	}
	int mid=(tree[rt].l+tree[rt].r)>>1;
	if(x<=mid)
		update(rt<<1,x,v);
	else
		update(rt<<1|1,x,v);
	pushup(rt);
}

SegTree ask(int rt,int x,int y)//询问[x,y]区间的连续最大值 
{
	if(x<=tree[rt].l && tree[rt].r<=y)
		return tree[rt];
	
	SegTree nl,nr,ans;
	nl.lmax = nl.rmax = nl.sum = nl.data = nr.lmax = nr.rmax = nr.data = nr.sum = -inf;
    ans.sum = 0;
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(x<=mid)
    {
    	nl = ask(rt << 1, x, y);
        ans.sum += nl.sum;
	}
	if(y>mid)
	{
		nr = ask(rt << 1 | 1, x, y);
        ans.sum += nr.sum;
	}
    ans.data = max(max(nl.data, nr.data), nl.rmax + nr.lmax);
    ans.lmax = max(nl.lmax, nl.sum + nr.lmax);
    ans.rmax = max(nr.rmax, nr.sum + nl.rmax);
    if(x > mid) ans.lmax = max(ans.lmax, nr.lmax);
    if(y <= mid) ans.rmax = max(ans.rmax, nl.rmax);
    return ans;
}

int main()
{
	qc;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	build(1,1,n);
	while(m--)
	{
		int opt,x,y;
		cin>>opt>>x>>y;
		if(opt==1)
		{
			if(x>y)
				swap(x,y);
			SegTree tmp=ask(1,x,y);
			cout<<tmp.data<<endl;
		}
		else
			update(1,x,y);
	}
	return 0;
}

碎碎念:

其实这个思路想出来并不难,要考虑三种情况然后取max,但是实现起来着实有点费事,怪我写代码能力太差了,orz

<think>好的,用户现在问的是参加蓝桥杯C++比赛是否需要用到数据结构。首先,我需要回顾之前的对话历史。用户之前询问过在信号与系统领域的科研中是否需要数据结构,我详细解释了数据结构在不同场景中的应用。现在用户转向比赛,特别是蓝桥杯,可能需要调整回答的角度,从科研转向竞赛。 接下来,我需要确定蓝桥杯比赛的具体要求。蓝桥杯是一个编程和算法竞赛,通常涉及大量的算法题,数据结构是其中的核心内容。参赛者需要解决各种问题,比如动态规划、图论、树结构等,这些都离不开数据结构的基础。 用户可能想知道数据结构在比赛中的重要性,是否需要重点学习。考虑到用户之前对科研中的应用感兴趣,现在转向竞赛,可能存在对数据结构通用性的疑问。用户可能希望了解数据结构在比赛中的具体应用场景,以及如何准备。 需要分析蓝桥杯的题目类型,通常包括填空题、编程题,涉及基础数据结构如数组、链表、栈、队列,以及高级结构如树、图、并查集、堆等。算法部分如排序、搜索、贪心、动态规划、图算法等都需要数据结构的支持。 用户可能作为C++选手,需要掌握STL中的数据结构实现,比如vector、queue、priority_queue、set、map等,这些在比赛中能节省编码时间,提高效率。同时,需要强调数据结构在解题中的实际例子,比如BFS使用队列,最短路径用Dijkstra算法需要优先队列等。 另外,用户可能担心不学数据结构是否会影响比赛成绩,需要指出不学的后果,比如解题效率低,无法通过某些测试用例,或者代码冗长易错。同时,给出学习建议,比如重点掌握哪些结构,如何练习,推荐资源等。 最后,总结数据结构在比赛中的必要性,强调其基础地位,并鼓励用户系统学习,结合刷题巩固知识。需要确保回答结构清晰,分点明确,有实际例子,帮助用户理解应用场景,同时提供可行的学习路径。</think>参加蓝桥杯等编程竞赛(尤其是C++组),**数据结构是必学内容**,甚至可以说是算法题的解题核心。以下是具体原因和应用场景分析: --- ### **1. 竞赛题目直接考察数据结构** 蓝桥杯题目中,约70%的题目需要**直接或间接使用数据结构**,例如: - **基础题**:数组、字符串操作(翻转、子串匹配)、栈和队列的应用(括号匹配、表达式求值)。 - **进阶题**:树(二叉树遍历、最近公共祖先)、图(最短路径、拓扑排序)、并查集(连通性问题)。 - **压轴题**:动态规划中的状态优化(如滚动数组)、贪心算法结合优先队列(堆)、高级数据结构线段树、字典树Trie)。 **典型题目示例**: - **迷宫最短路径** → **BFS(队列)** - **哈夫曼编码权重计算** → **优先队列(堆)** - **区间最大值查询** → **线段树或稀疏表** - **字符串模式匹配** → **KMP算法(需理解前缀函数)** --- ### **2. 数据结构算法优化的基础** - **时间复杂度优化**: 例如用**哈希表(unordered_map)** 将查找时间从O(n)降到O(1),或用**前缀和数组**将区间求和从O(n)优化到O(1)。 - **空间复杂度优化**: 如用**位运算压缩状态**代替多维数组,或用**链表**动态管理内存。 --- ### **3. C++ STL库依赖数据结构实现** C++的STL(标准模板库)提供了现成的数据结构实现,**熟练使用STL是竞赛关键**: - **vector**:动态数组,替代普通数组(支持快速随机访问)。 - **queue/stack**:直接用于BFS、DFS等场景。 - **priority_queue**:实现堆结构,用于贪心算法(如Dijkstra最短路径)。 - **set/map**:红黑树实现,维护有序数据(自动去重、二分查找)。 - **unordered_set/unordered_map**:哈希表实现,快速查找(需注意哈希冲突)。 **STL使用技巧**: ```cpp // 例:用优先队列实现小根堆(默认是大根堆) priority_queue<int, vector<int>, greater<int>> min_heap; ``` --- ### **4. 不学数据结构的后果** - **代码冗长易错**:手动实现队列、栈等结构会占用大量时间,且容易写出边界错误。 - **无法通过时间限制**:例如用O()暴力解法替代O(n log n)的排序+双指针,会导致超时。 - **难以解决复杂问题**:如线段树、并查集等题目几乎无法暴力破解。 --- ### **备赛学习建议** 1. **掌握核心数据结构**(按优先级排序): - **线性结构**:数组、链表、栈、队列、哈希表。 - **树与图**:二叉树、堆、并查集、图的邻接表表示。 - **高级结构**:线段树、字典树(视比赛难度选择)。 2. **结合算法学习**: - **排序与搜索**:快速排序、二分查找。 - **动态规划**:状态压缩(位运算、滚动数组)。 - **图论**:最短路径(Dijkstra、Floyd)、最小生成树(Kruskal、Prim)。 3. **刷题训练**: - **经典题库**:LeetCode、洛谷、AcWing(重点刷“数据结构”标签题)。 - **蓝桥杯真题**:研究历年试题(如《蓝桥杯历届真题解析》)。 4. **STL熟练度**: - 掌握STL容器的方法(如`emplace_back`与`push_back`的区别)。 - 避免常见坑点(如`map`的`[]`操作符可能插入新键值)。 --- ### **总结** 在蓝桥杯等竞赛中,**数据结构是解题的“工具箱”**: - 初级题:直接考察基础结构(如栈、队列); - 中级题:需要组合数据结构(如哈希表+滑动窗口); - 高级题:依赖高效数据结构(如线段树优化区间操作)。 **建议策略**: 1. **优先掌握STL的应用**(节省编码时间), 2. **理解底层原理**(应对变形题或需要手写结构的场景), 3. **通过大量刷题建立条件反射**(快速匹配题目与数据结构)。 即使是面向对象的C++,比赛中也更注重**效率与代码简洁性**,而数据结构正是实现这一目标的核心工具。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值