http://hihocoder.com/problemset/problem/1586
线段树,单点更新,区间查询极值。
给你一个数组,
有下面操作
输入 a b c
若为1,那么再b-c中找两个数,让他们的乘积最小。
若为2,那么把 a[b]=c;
乘积最小这个。。
因为有正负数。所以需要
min*min1 max1*max1 max1*min1 的最小值。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
/*
。。值就是 min*max
min*min 和max*max这么中间的最小值。。
线段树,总结一下板子把。。
这个结论没有想到。。
*/
const int maxn=1e6;
ll mins[maxn*4];
ll maxs[maxn*4];
const int inf=1e5;
void build(ll id,ll l,ll r)
{
ll m;
if(l==r)
{
scanf("%lld",&maxs[id]);
mins[id]=maxs[id];
return ;
}
m=(l+r)/2;
build(id<<1,l,m);
build((id<<1)+1,m+1,r);
maxs[id]=max(maxs[id*2],maxs[id*2+1]);
mins[id]=min(mins[id*2],mins[id*2+1]);
}
ll query(ll id,ll l,ll r,ll L, ll R)
{
ll ret=-inf;
if(l<=L && r>=R)
return maxs[id];
ll m=(L+R)/2;
if(l<=m)
ret=max(ret,query(id<<1,l,r,L,m));
if(r>m)
ret=max(ret,query((id<<1)+1,l,r,m+1,R));
return ret;
}
ll query1(ll id,ll l,ll r,ll L, ll R)
{
ll ret=inf;
if(l<=L && r>=R){
//cout<<mins[id]<<"res"<<endl;
return mins[id];}
ll m=(L+R)/2;
if(l<=m)
ret=min(ret,query1(id<<1,l,r,L,m));
if(r>m)
ret=min(ret,query1((id<<1)+1,l,r,m+1,R));
return ret;
}
void update(ll x,ll y,ll l,ll r,ll id)
{
if(l==r)
{
maxs[id]=y;
mins[id]=y;
return ;
}
ll m=(l+r)/2;
if(x<=m)
update(x,y,l,m,id*2);
else
update(x,y,m+1,r,id*2+1);
maxs[id]=max(maxs[id*2],maxs[id*2+1]);
mins[id]=min(mins[id*2],mins[id*2+1]);
}
int main()
{ ll t,m,n,a,b,c;
scanf("%lld",&t);
while(t--){
scanf("%lld",&m);
m=(int)pow(2,m);
build(1,1,m);
scanf("%lld",&n);
for(int i=0;i<n;i++){
scanf("%lld%lld%lld",&a,&b,&c);
if(a==1){
b++;c++;
//cout<<b<<"*****"<<c<<endl;
ll ans1=query(1,b,c,1,m);
ll ans2=query1(1,b,c,1,m);
//cout<<ans1<<"**"<<ans2<<endl;
ll all=min(ans1*ans1,ans2*ans2);
all=min(all,ans1*ans2);
printf("%lld\n",all);
}
else{
update(b+1,c,1,m,1);
}
}
}
return 0;
}