线段树 ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛 HihoCoder 1586

本文介绍了一种利用线段树解决特定查询问题的方法,包括查询区间内两数乘积最小值及更新指定位置数值。通过构建线段树并实现更新与查询操作,有效地解决了复杂的数据结构问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#1586 : 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

题意:给出一个数组,有多次查询,查询类型1 : 问区间(l,r)里找两个数使乘积最小,(可以重复使用数字)

查询类型2:把下标为 x 的值该为 c

思路:用线段树维护一个区间的最大值和最小值,查询答案的时候定位到这个区间,然后根据最大值和最小值的正负找到最小的组合,输出答案即可

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
#define maxn 500005

struct Tree{
	int minn,maxx,l,r;
}tree[maxn * 4];
int arr[maxn * 4];

void push_up(int i){
	tree[i].maxx = max(tree[i << 1].maxx,tree[i << 1 | 1].maxx);
	tree[i].minn = min(tree[i << 1].minn,tree[i << 1 | 1].minn);
}
void build(int l,int r,int i){
	tree[i].l = l;
	tree[i].r = r;
	int mid = (l + r) >> 1;
	if(l == r){
		tree[i].maxx = tree[i].minn = arr[l];
	}else{
		build(l,mid,i << 1);
		build(mid + 1,r,i << 1 | 1);
		push_up(i);
	}
}

void update(int x,int c,int i){
	if(tree[i].l == x && tree[i].r == x){
		tree[i].maxx = tree[i].minn = c;
		return ;
	}
	int mid = (tree[i].l + tree[i].r) >> 1;
	if(mid >= x)
		update(x,c,i << 1);
	else if(mid < x){
		update(x,c,i << 1 | 1);
	}else{
		update(x,c,i << 1);	
		update(x,c,i << 1 | 1);
	}
	push_up(i);
}

Tree query(int x,int y,int i){
	if(x <= tree[i].l && tree[i].r <= y){
		return tree[i];
	}
	int mid = (tree[i].l + tree[i].r) >> 1;
	if(mid >= y){
		return query(x,y,i << 1);
	}else if(mid < x){
		return query(x,y,i << 1 | 1);
	}else{
		Tree t1,t2,tmp;
		t1 = query(x,y,i << 1);
		t2 = query(x,y,i << 1 | 1);
		tmp.maxx = max(t1.maxx,t2.maxx);
		tmp.minn = min(t1.minn,t2.minn);
		return tmp; 
	}
}
int main(){
	int n,m,a,b,c,t;
	ll ans;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		n = 1 << n;
		for(int i = 1;i <= n;i++){
			scanf("%d",&arr[i]);
		}
		build(1,n,1);
		scanf("%d",&m);
		while(m--){
			scanf("%d %d %d",&a,&b,&c);
			if(a == 1){
				Tree tmp = query(b + 1,c + 1,1);
				if(tmp.minn <= 0 && tmp.maxx >= 0){
					ans = (ll)tmp.maxx * tmp.minn;
				}else if(tmp.minn < 0 && tmp.maxx <= 0)
					ans = (ll)tmp.maxx * tmp.maxx;
				else
					ans = (ll)tmp.minn * tmp.minn;
				printf("%lld\n",ans);
			}else{
				update(b + 1,c,1);
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值