描述

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, -2k ≤ 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.最大值的平方(最大值为负数)
2.最小值的平方(最小值为正数)
3.最大值与最小值的乘积(最大值是正,最小值为负)
得到此结果后,只需改一下线段树的模板,将每段区间的最大最小值保存下来即可。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 const long long Max=140000;
 7 int n;
 8 struct node
 9 {
10     long long b,s;
11 }Tree[Max<<2];
12 long long bb,ss;
13 void build(int k,int l,int r)//建线段树,k表示子节点坐标
14 {
15     if(l == r) 
16     {
17         scanf("%lld",&Tree[k].b);
18         Tree[k].s=Tree[k].b;
19     }
20     else
21     {
22         int mid = (l+r)/2;
23         build(k*2,l,mid);
24         build(k*2+1,mid+1,r);
25         Tree[k].b=max(Tree[k*2].b, Tree[k*2+1].b);
26         Tree[k].s=min(Tree[k*2].s, Tree[k*2+1].s);
27     }
28 }
29 void query(int a,int b,int k,int l,int r)//a,b是当前查询区间,k是当前的根节点,l,r是要求查询区间
30 {
31     if(a >= l && b <= r) 
32     {
33         bb=max(bb,Tree[k].b);
34         ss=min(ss,Tree[k].s);
35         //return min(min(Tree[k].b*Tree[k].b,Tree[k].b*Tree[k].s),Tree[k].s*Tree[k].s);
36         return;
37     }
38     else
39     {
40         //long long ans = Max*Max;
41         int mid = (a+b)/2;
42         if(l <= mid)query(a,mid,k*2,l,r);
43         if(r > mid) query(mid+1,b,k*2+1,l,r);
44         return;
45         //return ans;
46     }
47 }
48 void update(int l,int r,int k,int pos,long long v)//l,r是查询区间,k是当前根节点,pos是查询位置
49 {
50     if(l == r)
51     {
52         Tree[k].b=v;
53         Tree[k].s=v;
54     }
55     else{
56         int mid = (l+r)/2;
57         if(pos <= mid) update(l,mid,k*2,pos,v);
58         if(pos > mid) update(mid+1,r,k*2+1,pos,v);
59         Tree[k].b=max(Tree[k*2].b, Tree[k*2+1].b);
60         Tree[k].s=min(Tree[k*2].s, Tree[k*2+1].s);
61     }
62 }
63 
64 int main()
65 {
66     int T,l,r,pos;
67     long long val;
68     int k,c,order;
69     scanf("%d",&T);
70     for(int t=1;t<=T;t++)
71     {
72         
73         scanf("%d",&k);
74         n=pow(2.0,k);
75         build(1,1,n);
76         scanf("%d",&c);
77         while(c--)
78         {
79             scanf("%d",&order);
80             if(order==1)
81             {
82                 scanf("%d%d",&l,&r);
83                 bb=-Max;ss=Max;
84                 long long tmpans;
85                 query(1,n,1,l+1,r+1);
86                 tmpans= min(min(bb*bb,bb*ss),ss*ss);
87                 printf("%lld\n",tmpans);
88             }
89             else if(order==2)//点更新
90             {
91                 scanf("%d%lld",&pos,&val);
92                 update(1,n,1,pos+1,val);
93             }
94         }
95     }
96     return 0;
97 }