北京赛区(2017)网络赛 之 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

分析:x,y属于区间[l,r],求最小的ax*ay,分一下情况,五种情况   [-,-]   [-,0]   [-,+]   [0,+]   [+,+]

查询操作次数最大有2^17=131072,  因此每次操作必须在常数时间o(n)内算出结果,因此要用到线段树


AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
const int MAXN=200001;
typedef long long llint;

struct Tree{
	int l,r,s;
}nod[MAXN*4];
int a[MAXN];
void creat (int t,int l,int r)
{
	nod[t].l=l;
	nod[t].r=r;
	if(l==r){
		nod[t].s=a[l];
		return;
	}
	int m=(l+r)/2;
	creat(t*2,l,m);
	creat(t*2+1,m+1,r);
	nod[t].s=min(nod[t*2].s,nod[t*2+1].s);
}
void update (int t,int n,int v)//把n点的值更新为v;
{
	if(nod[t].r==nod[t].l&&nod[t].r==n)
	{
		nod[t].s=v;
		return;
	}
	int mid = (nod[t].l+nod[t].r)>>1;
	if(n<=mid)  update (t*2,n,v);
	else    update(2*t+1,n,v);
	nod[t].s=min(nod[2*t].s,nod[2*t+1].s);
}
int query(int t,int l,int r){
	if(l==nod[t].l&&r==nod[t].r)
	   return nod[t].s;
    int mid = (nod[t].l+nod[t].r)>>1;
	if(r<=mid)
	   return query(t*2,l,r);
	else if(l>mid)
	  return query(2*t+1,l,r);
	else
	return min(query(2*t,l,mid),query(t*2+1,mid+1,r));
}
struct Tree1{
	int l,r,s;
}nod1[MAXN*4];
void creat1 (int t,int l,int r)
{
	nod1[t].l=l;
	nod1[t].r=r;
	if(l==r){
		nod1[t].s=a[l];
		return;
	}
	int m=(l+r)/2;
	creat1(t*2,l,m);
	creat1(t*2+1,m+1,r);
	nod1[t].s=max(nod1[t*2].s,nod1[t*2+1].s);
}
void update1(int t,int n,int v)//把n点的值更新为v;
{
	if(nod1[t].r==nod1[t].l&&nod1[t].r==n)
	{
		nod1[t].s=v;
		return;
	}
	int mid = (nod1[t].l+nod1[t].r)>>1;
	if(n<=mid)  update1 (t*2,n,v);
	else    update1(2*t+1,n,v);
	nod1[t].s=max(nod1[2*t].s,nod1[2*t+1].s);

}
int query1(int t,int l,int r){
	if(l==nod1[t].l&&r==nod1[t].r)
	   return nod1[t].s;
    int mid = (nod1[t].l+nod1[t].r)>>1;
	if(r<=mid)
	   return query1(t*2,l,r);
	else if(l>mid)
	  return query1(2*t+1,l,r);
	else
	return max(query1(2*t,l,mid),query1(t*2+1,mid+1,r));
}
int main(){

	int N;
	cin>>N;
	while(N--)
	{
		int n,m,i,x1,x2;
       	int s;
	    cin>>n;
	    int num=pow(2.0,n);
		for(i=1;i<=num;i++)
		  scanf("%d",&a[i]);
		  creat(1,1,pow(2.0,n));
		  creat1(1,1,pow(2.0,n));
		  cin>>m;
		  while(m--){
		  	scanf("%d%d%d",&s,&x1,&x2);
		  	if(s==1)
		  	{
		  	    int mini=query(1,x1+1,x2+1);//查最小值
		  	    int maxi=query1(1,x1+1,x2+1);//查最大值
		  	    if(mini<0 && maxi<0) cout<<(llint)maxi*maxi<<endl;
		  	    else if(mini>0 && maxi>0) cout<<(llint)mini*mini<<endl;
		  	    else if(mini<0 && maxi>0) cout<<(llint)maxi*mini<<endl;
		  	    else if(maxi==0) cout<<0<<endl;
		  	    else if(mini==0) cout<<0<<endl;
            }
		  	else
		  	{
		  		update(1,x1+1,x2);//更新
		  		update1(1,x1+1,x2);//更新
            }

		  }
	}
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值