线段树模板题

题目:http://poj.org/problem?id=3264

题目大意:

给定一个n和m ,输入n,包含n行 代表1~n牛的重量,然后m行,输入p,q,查询在序号为p~q中最大重量的牛和和最小重量的牛之间的差值

题解:

1.首先要注意的是 输入的数据量较大且输入次数较多 因此采用scanf(%d,&a)和printf(%d,&a)进行输入输出 防止超时 

2.本题属于区间单点修改和区间查询的题目类型,因此采用线段树做法

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
typedef long long ll;
struct Tree
{
	ll l, r;
	ll maxx, minn;
	ll mid() { return (l + r) / 2; }
}tree[800010];
ll maxv = -10000000;
ll minv = 10000000;
void BuildTree(int root, int l, int r)
{
	tree[root].l = l;
	tree[root].r = r;
	tree[root].maxx = -10000000;
	tree[root].minn = 10000000;
	//建立左右子树
	if (l!= r)
	{
		BuildTree(root * 2+1, l, (l+r)/2);
		BuildTree(root * 2 + 2, (l+r)/2 + 1, r);
	}
}
//i为要插入的序号 v为要插入的值 采用二分的方法
void insert(ll root,ll i,ll v)
{
	if (tree[root].l==tree[root].r)
	{
		tree[root].maxx = v;
		tree[root].minn = v;
		return;
	}
	tree[root].maxx = max(tree[root].maxx, v);
	tree[root].minn = min(tree[root].minn, v);
	if (i <= tree[root].mid())
	{
		insert(2*root+1,i,v);
	}
	else
	{
		insert(2 * root + 2, i, v);
	}
}
void query(ll root, ll s, ll e)
{
	//回溯 满足以下条件 无需再往下进行查找
	if (tree[root].maxx <= maxv && tree[root].minn >= minv)
	{
		return;
		
	}
	if (tree[root].l == s && tree[root].r == e)
	{
		maxv = max(tree[root].maxx, maxv);
		minv = min(tree[root].minn, minv);
		return;
	}
	/*
	若目标区间只位于左区间 则只查询左子树
	第二个同理
	否则左右子树均查询
	*/
	if (e <= tree[root].mid())
	{
		query(2 * root + 1, s, e);
	}
	else if (s > tree[root].mid())
	{
		query(2 * root + 2, s, e);
	}
	else
	{
		query(2 * root + 1, s, tree[root].mid());
		query(2 * root + 2, tree[root].mid()+1, e);
	}
}

int main()
{
	ll n, m;
	scanf("%lld%lld", &n, &m);
	BuildTree(0, 1, n);
	for (int i = 0; i < n; i++)
	{
		ll q;
		scanf("%lld", &q);
		insert(0, i + 1, q);
	}
	for (int i = 0; i < m; i++)
	{
		ll st; 
		scanf("%lld", &st);
		ll en; 
		scanf("%lld", &en);
		minv = 100000000;
		maxv = -10000000;
		query(0, st, en);
		printf("%lld\n", maxv - minv);
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值