HDU 5443 模拟 线段树 区间查询*

模拟

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define ll long long
#define MAXN 100
int t;
int n;
int water[1000+1];
int query_num;
int l, r;
int main()
{ 
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", water + i);
		}
		scanf("%d", &query_num);
		for (int i = 0; i < query_num; i++)
		{
			scanf("%d%d", &l, &r);
			int maxx = 0;
			for (int j = l; j <= r; j++)
			{
				maxx = max(maxx, water[j]);
			}
			printf("%d\n", maxx);
		}
	}
	return 0;
}

线段树,用模拟的方法复杂度是On 线段树的方法可以达到Olgn
线段树的基础用法主要分为
区间查询:例如这里要查询一个区间[query_l,query_r]的最大值,对于树中的一个结点表示的区间[l,r]如果[query_l,query_r]包含[l,r]则,[l,r]的最大值,就是[query_l,query_r]的最大值,如果两个区间没有交集,最大值自然是0。
如果两个集合有交集(也有可能[l,r]包含区间[query_l,query_r]),那么就要把[query_l,query_r]区间分成树中基础的区间。如何体现这些基础的区间能够组成[query_l,query_r]这个区间呢,也就是上文的包含关系,若[query_l,query_r]包含了[l,r]区间,则[l,r]能够和其他基础区间组成[query_l,query_r]则max(query_l,query_r)=max((l1,r1)(l2,r2)……)(基础区间)
实际上线段树将On的复杂度将为Olgn的复杂度的方法和二进制,思想上也是二分
例如要求一个数30,可以+1 30次,也可以+16,+8 +4 +2只要加4次就可以了,
单点查询,就像二分查找一样,递归查找叶子结点
单点修改,先递归查找找到这个叶子结点,再回溯到根节点,更新该叶子结点所有父节点的值
区间修改:对一个区间修改,即将该区间上的所有值加1,若是采取传统的方法,对该结点的所有子节点更新一遍,那时间复杂度太高,比如1到10000区间加1,那左子树和右子树都要加1,子树的左子树和右子树都要加1,时间复杂度要达到10000logn。其次,如果我们全部加了一遍,但是查询的时候又没有查到,就浪费了。我们采取这样的策略,设一个标志lazy_tag,将加的值delta,加到lazy_tag上,然后更新该结点(代表要增加值的区间)的值,同时将他的父节点的值也更新一下。然后当要查询到他的子节点的时候,把他的lazy_tag下移,他的lazy_tag变为0,字节点的lazy-tag变为刚刚的值,更新子节点的值。
然后关于为什么线段树的操作是lgn,可以这样说明。
单词修改,单点查询,区间修改很好理解,因为树的高度就是logn
区间查询中,当区间位于该结点Mid的两侧,则他可以分成左右的字节的。假设他分成了左右的子节点,那么下一步每步最多再分成两个,也就是说下一步最多访问4个点,再下一步也只会访问四个点
比如访问[l,r]区间,若待查区间为[x,y]其中mid>=x&&mid<=y
则访问[l,mid] [mid+1,r]
我们关注[l,mid]这个区间,它只有两种情况
1.待查区间在[l,mid]中的部分位于[l,mid]的右边,则它只会访问一侧结点,即x>=(l+mid)/2
2.待查区间在[l,mid]中的部分为[l,mid]的右边一半,加上[l,mid]左边靠右的一部分
即x<(l+mid)/2,则它访问两侧结点,左子结点,和右子节点,但是右子节点,但右子结点被覆盖了,不会再往下延申了。同时[mid+1,r]区间也是这样
所以每层最多访问4个结点
所以区间查询的时间复杂度为O(4lgn)即O(lgn)
5443只涉及了区间查询

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define ll long long
#define MAXN 1000
typedef struct tree_node
{
	int l, r;
	int maxx;
}tree_node;
tree_node tree[4 * MAXN+1];
int t;
int n;
int num[MAXN+1];
int query_num;
int l, r;
void build(int index, int l, int r)
{
	tree[index].l = l;
	tree[index].r = r;
	if (l == r)
	{
		tree[index].maxx = num[l];
		return;
	}
	build(2 * index, l, (l + r) / 2);
	build(2 * index + 1, (l + r) / 2 + 1, r);
	tree[index].maxx = max(tree[2 * index].maxx, tree[2 * index + 1].maxx);
}
int query(int index,int l, int r,int query_l,int query_r)
{
	if (query_l > r || query_r < l)
	{
		return 0;
	}
	if (query_l <= l && query_r >= r)
	{
		return tree[index].maxx;
	}
	int t1=query(2 * index, l, (l + r) / 2, query_l, query_r);
	int t2 = query(2 * index + 1, (l + r) / 2 + 1, r, query_l, query_r);
	return max(t1, t2);
}
int main()
{ 
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", num + i);
		}
		build(1, 1, n);
		/*
		for (int i = 1; i <= 4 * MAXN + 1; i++)
		{
			if (tree[i].maxx == 0)
				break;
			printf("第%d个结点的值是%d,区间是[%d,%d],左孩子标号是%d,右孩子标号是%d\n", i,tree[i].maxx, tree[i].l, tree[i].r, 2 * i, 2 * i + 1);
		}
		*/

		scanf("%d", &query_num);
		for (int i = 0; i < query_num; i++)
		{
			scanf("%d%d", &l, &r);
			printf("%d\n", query(1, 1, n, l, r));
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值