2017ICPC北京网络赛Minimum(线段树+区间最值)

题目9 : Minimum

时间限制: 1000ms
单点时限: 1000ms
内存限制: 256MB

描述

You are given a list of integers a0, a1, …, a2^k-1.

You need to support two types of queries:

1. Output Minx,y∈[l,r] {ax∙ay}.

2. Let ax=y.

输入

The first line is an integer T, indicating the number of test cases. (1≤T≤10).

For each test case:

The first line contains an integer k (0 ≤ k ≤ 17).

The following line contains 2k integers, a0, a1, …, a2^k-1 (-2k ≤ ai < 2k).

The next line contains a integer  (1 ≤ Q < 2k), indicating the number of queries. Then next Q lines, each line is one of:

1. 1 l r: Output Minx,y∈[l,r]{ax∙ay}. (0 ≤ l ≤ r < 2k)

2. 2 x y: Let ax=y. (0 ≤ x < 2k, -2≤ y < 2k)

输出

For each query 1, output a line contains an integer, indicating the answer.

样例输入
1
3
1 1 2 2 1 1 2 2
5
1 0 7
1 1 2
2 1 2
2 2 2
1 1 2
样例输出
1
1
4

线段树,求个区间乘积的最小值。因为值可能是负数,所以要分情况讨论。



#include <cstdio>
#include <algorithm>
using namespace std;

#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 200000;
int MAX[maxn << 2];
int MIN[maxn << 2];
int pos;
//区间最大值
void PushUP1(int rt) {
	MAX[rt] = max(MAX[rt << 1], MAX[rt << 1 | 1]);
}
void build1(int l, int r, int rt) {
	if (l == r) {
		scanf("%d", &MAX[rt]);
		MIN[rt] = MAX[rt];
		return;
	}
	int m = (l + r) >> 1;
	build1(lson);
	build1(rson);
	PushUP1(rt);
}
void update1(int p, int sc, int l, int r, int rt) {
	if (l == r) {
		MAX[rt] = sc;
		return;
	}
	int m = (l + r) >> 1;
	if (p <= m) update1(p, sc, lson);
	else update1(p, sc, rson);
	PushUP1(rt);
}
int query1(int L, int R, int l, int r, int rt) {
	if (L <= l && r <= R) {
		return MAX[rt];
	}
	int m = (l + r) >> 1;
	int ret = -maxn;
	if (L <= m) ret = max(ret, query1(L, R, lson));
	if (R > m) ret = max(ret, query1(L, R, rson));
	return ret;
}
//区间最小值
void PushUP2(int rt) {
	MIN[rt] = min(MIN[rt << 1], MIN[rt << 1 | 1]);
}
void build2(int l, int r, int rt) {
	if (l == r) {
		return;
	}
	int m = (l + r) >> 1;
	build2(lson);
	build2(rson);
	PushUP2(rt);
}
void update2(int p, int sc, int l, int r, int rt) {
	if (l == r) {
		MIN[rt] = sc;
		return;
	}
	int m = (l + r) >> 1;
	if (p <= m) update2(p, sc, lson);
	else update2(p, sc, rson);
	PushUP2(rt);
}
int query2(int L, int R, int l, int r, int rt) {
	if (L <= l && r <= R) {
		return MIN[rt];
	}
	int m = (l + r) >> 1;
	int ret = maxn;
	if (L <= m) ret = min(ret, query2(L, R, lson));
	if (R > m) ret = min(ret, query2(L, R, rson));
	return ret;
}
int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		pos = 1;
		int k;
		scanf("%d", &k);
		//节点个数
		for (int i = 0; i < k; i++)
		{
			pos *= 2;
		}
		build1(1, pos, 1);
		build2(1, pos, 1);
		int q;
		scanf("%d", &q);
		while (q--)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			if (a == 2)
			{//更新
				update1(b + 1, c, 1, pos, 1);
				update2(b + 1, c, 1, pos, 1);
			}
			if (a == 1)
			{
				long long min1 = query2(b + 1, c + 1, 1, pos, 1);
				long long max1 = query1(b + 1, c + 1, 1, pos, 1);
				long long ans;
				
				if (min1 <= 0&&max1>=0)//最小负数乘最大正数最小
				{
					ans = min1*max1;
				}
				else if (min1 > 0)//最小正数乘最小正数最小
				{
					ans = min1*min1;
				}
				else if ( max1 < 0)//最大负数乘最大负数最小
				{
					ans = max1*max1;

				}
				printf("%lld\n", ans);
			}

		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值