2017ICPC网络赛北京赛区 I题
描述
You are given a list of integers a0, a1, …, a2^k-1.
You need to support two types of queries:
Output Minx,y∈[l,r] {ax∙ay}.
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 l r: Output Minx,y∈[l,r]{ax∙ay}. (0 ≤ l ≤ r < 2k)
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求区间内最小的ax*ay,ax,ay可以相等。要注意ai的大小可以是负数,所以要进行分类讨论。当ai全部是负数的时候,答案是最大值x最大值;当ai全部是正数的时候,答案是最小值x最小值;当ai有正有负的时候,答案是最大值x最小值。
#include
#include
#include
#include
#include
#define N 100010
using namespace std;
typedef long long ll;
ll a[1500000];
struct Tree{
ll l,r;
ll sum,add,num,maxn;//num记录最小值
}tree[1500000];
//延迟更新
void pushup(ll root){//儿子把信息传递给父亲
//if(tree[root].l==tree[root].r)return ;
//tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum; //<<1:*2; <<1|1:*2+1\
tree[root].num=min(tree[root<<1].num,tree[root<<1|1].num);
tree[root].maxn=max(tree[root<<1].maxn,tree[root<<1|1].maxn);
return ;
}
void pushdown(ll root){//父亲把自己的信息传给儿子
if(tree[root].l==tree[root].r)return ;
if(tree[root].add==-1)return ;
tree[root<<1].add=tree[root<<1|1].add=tree[root].add;
tree[root<<1].maxn=tree[root<<1|1].maxn=tree[root].maxn;
tree[root<<1].num=tree[root<<1|1].num=tree[root].num;
tree[root].add=-1;
return ;
}
//初始化
void build(ll l,ll r,ll root){
tree[root].l=l;
tree[root].r=r;
tree[root].sum=0;
tree[root].num=0;
tree[root].maxn=0;
tree[root].add=-1;
if(l==r){//直到单个区间位置
tree[root].sum=a[l];
tree[root].num=a[l];
tree[root].maxn=a[l];
// printf("%lld %lld\n",l,tree[root].num);
return;
}
ll mid=(l+r)>>1;
build(l,mid,root<<1);//左区间
build(mid+1,r,root<<1|1); //右区间
pushup(root);//把儿子的信息更新到父亲
//tree[root].num=min(tree[root<<1].num,tree[root<<1|1].num);
//tree[root].maxn=max(tree[root<<1].maxn,tree[root<<1|1].maxn);
return;
}
//更新区间
void update(ll l,ll r,ll z,ll root){
if(l==tree[root].l&&tree[root].r==r){
//tree[root].sum=(tree[root].r-tree[root].l+1)*z;
tree[root].num=z;
tree[root].maxn=z;
tree[root].add=z;//把要更新的内容保存下来,等到要用儿子时 再去更新
return ;
}
pushdown(root);//用父亲的信息更新儿子
ll mid=tree[root].l+tree[root].r>>1;
if(r<=mid)update(l,r,z,root<<1);
else if(l>mid)update(l,r,z,root<<1|1);
else {
update(l,mid,z,root<<1);
update(mid+1,r,z,root<<1|1);
}
pushup(root);//更新父亲
//tree[root].num=min(tree[root<<1].num,tree[root<<1|1].num);
//tree[root].maxn=max(tree[root<<1].maxn,tree[root<<1|1].maxn);
return ;
}
//查找区间信息
ll query1(ll l,ll r,ll root){
if(l<=tree[root].l&&tree[root].r<=r){
return tree[root].num;
}
pushdown(root);
ll mid=tree[root].l+tree[root].r>>1;
if(r<=mid)return query1(l,r,root<<1);
else if(l>mid)return query1(l,r,root<<1|1);
else return min(query1(l,mid,root<<1),query1(mid+1,r,root<<1|1));
}
ll query2(ll l,ll r,ll root){
if(l<=tree[root].l&&tree[root].r<=r){
return tree[root].maxn;
}
pushdown(root);
ll mid=tree[root].l+tree[root].r>>1;
if(r<=mid)return query2(l,r,root<<1);
else if(l>mid)return query2(l,r,root<<1|1);
else return max(query2(l,mid,root<<1),query2(mid+1,r,root<<1|1));
}
int main(){
ll n,k,t;
scanf("%lld",&t);
while(t--){
scanf("%lld",&k);
n=1<//prllf("%lld\n",n);
for(ll i=0;iscanf("%lld",&a[i]);
build(0,n-1,1);
ll q;
scanf("%lld",&q);
while(q--)
{
ll tag;
scanf("%lld",&tag);
if(tag==1)
{
ll x,y,ans;
scanf("%lld%lld",&x,&y);
ll minn=query1(x,y,1);
ll mann=query2(x,y,1);
//printf("%lld %lld\n",minn,mann);
if(mann<=0)
{
ans=mann*mann;
}
else if(minn>=0)
{
ans=minn*minn;
}
else
{
ans=mann*minn;
}
printf("%lld\n",ans);
}
else
{
ll x,y;
scanf("%lld%lld",&x,&y);
update(x,x,y,1);
}
}
}
return 0;
}