ACM 粗心永远AC不了系列——HDU 1754 I Hate It|线段树区间求最值

9 篇文章 0 订阅
9 篇文章 0 订阅

线段树应用水题之一

一:线段树基本概念

1:概述

线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)!

性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍

2:基本操作(demo用的是查询区间最小值)

线段树的主要操作有:

(1):线段树的构造 void build(int node, int begin, int end);

(2):区间查询int query(int node, int begin, int end, int left, int right);

(3):区间或节点的更新 及 线段树的动态维护update (这是线段树核心价值所在,节点中的标记域可以解决N多种问题)

动态维护需要用到标记域,延迟标记等。

3:主要应用

(1):区间最值查询问题 (见模板1)

(2):连续区间修改或者单节点更新的动态查询问题 (见模板2)

(3):多维空间的动态查询 (见模板3)

具体线段树ACM情况可以参看转载博客:数据结构专题——线段树

题目来源:I Hate It

ac代码:

#pragma warning(disable:4996)  
#include <stdio.h>  
#include <algorithm>
using namespace std;
#define MAXN 200000 + 10
int a[MAXN];
struct Node
{
	int l = 0, r = 0, v = 0;
}tree[800010];//注意数组一定要开大,之前开了400010,结果愣是超时,改了20+次才发现数组开的不够大,粗心
void build(int i, int l, int r) {
	tree[i].l = l;
	tree[i].r = r;
	if (l == r){
		tree[i].v = a[l];
		return;// 叶子节点退出
	}
	int mid = (r + l) >> 1;
	build(i << 1, l, mid);// 建立左子树 数组完全二叉树 i*2==i<<1
	build(i << 1 | 1, mid + 1, r);// 建立右子树 数组完全二叉树 i*2+1==i<<1|1
	tree[i].v = max(tree[i << 1].v, tree[i << 1 | 1].v);
}
void update(int num, int x, int v) {
	if (tree[num].l == x && tree[num].r == x) {
		tree[num].v = v;
		return;
	}
	int mid = (tree[num].l + tree[num].r) >> 1;
	if (x > mid)
		update(num << 1 | 1, x, v);
	else
		update(num << 1, x, v);
	tree[num].v = max(tree[num << 1].v, tree[num << 1 | 1].v);
}
int query(int i, int left, int right) {
	if (tree[i].l == left && tree[i].r == right) {
		return tree[i].v;
	}
	int mid = (tree[i].l + tree[i].r) >> 1;
	if (right <= mid)
		return query(i << 1, left, right);
	else if (left >= mid + 1)
		return query(i << 1 | 1, left, right);
	else {
		int le = query(i << 1, left, mid);
		int ri = query(i << 1 | 1, mid + 1, right);
		return max(le, ri);
	}
}
int main()
{
	int n, m;
	char s[5];
	while (~scanf("%d%d", &n, &m))
	{
		for (int i = 1; i <= n; ++i)
		{
			scanf("%d", a + i);
		}
		build(1, 1, n);
		for (int i = 0; i < m; ++i)
		{
			scanf("%s", s);
			int a, b;
			scanf("%d%d", &a, &b);
			if (s[0] == 'Q')
				printf("%d\n", query(1, a, b));
			else if (s[0] == 'U')
				update(1, a, b);
		}
	}
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值