ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛 Minimum

来源:互联网 发布:大阿亚图拉知乎 编辑:程序博客网 时间:2024/06/05 17:12

题目链接
描述
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 2^k integers, a0, a1, …, a2^k-1 (-2^k ≤ ai < 2^k).
The next line contains a integer (1 ≤ Q < 2^k), 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 < 2^k)
2. 2 x y: Let ax=y. (0 ≤ x < 2^k, -2^k ≤ y < 2^k)
输出
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.<<运算符
举个例子:
5<<2 将5转化为二进制为101,"<<"的意思就是将5的二进制向左移动两位,右边补零
例子中移完之后,变成10100 结果就是20
或者直接记公式:a<<b = a×2^b;
2.>>运算符
同理:a>>b = a ÷ 2 ^ b;
3.线段树的节点数目要开存放数组最大限度的至少4倍(百度一下,你就知道)
4.如果线段树的某个节点为segTree[i],那么左孩子节点为segTree[2*i],右孩子节点为segTree[2*i+1],原因:
节点是从1开始的,例如第一个节点,没有第0个节点的说法
5.剩下的解释都在代码里

#include<algorithm>#include<iostream>#include<climits>#include<cstring>#include<cstdio>using namespace std;const int mx = 150000;int xx[mx];typedef struct Node{    int maxx;    int minn;}Node;//定义线段树Node tt[mx<<2];void build(int nstart,int nend,int rt){    if(nstart==nend){//叶子节点        tt[rt].maxx = xx[nstart];        tt[rt].minn = xx[nstart];        return;    }    int mid = (nstart + nend) >> 1;    //递归调用左子树    build(nstart,mid,rt<<1);    //递归调用右子树    build(mid+1,nend,rt<<1|1);    //比较左右子树上的最小值    tt[rt].maxx = max(tt[rt<<1].maxx,tt[rt<<1|1].maxx);    tt[rt].minn = min(tt[rt<<1].minn,tt[rt<<1|1].minn);}int query_max(int qstart,int qend,int nstart,int nend,int rt){    if(qstart>nend||qend<nstart)         /*        这里要特别注意:因为是求最大值,所以如果不在此区间的话,要把返回值设置为最小        ,只有这样,用max比较的时候才能把最大值比较出来        */        return INT_MIN;    if(qstart<=nstart&&qend>=nend)        return tt[rt].maxx;    int mid = (nstart + nend)>>1;    return max(query_max(qstart,qend,nstart,mid,rt<<1),query_max(qstart,qend,mid+1,nend,rt<<1|1));}int query_min(int qstart,int qend,int nstart,int nend,int rt){    if(qstart>nend||qend<nstart)         /*        这里要特别注意:因为是求最小值,所以如果不在此区间的话,要把返回值设置为最大        ,只有这样,用min比较的时候才能把最小值比较出来        */        return INT_MAX;    if(qstart<=nstart&&qend>=nend)        return tt[rt].minn;    int mid = (nstart + nend)>>1;    //递归的时候我们要查找的区间不能动,动的是原来数组代表的区间,    //这个特别注意    return min(query_min(qstart,qend,nstart,mid,rt<<1),query_min(qstart,qend,mid+1,nend,rt<<1|1));}void updata(int index,int change,int nstart,int nend,int rt){    if(nstart==nend){        tt[rt].maxx = change;        tt[rt].minn = change;        return;    }    int mid = (nstart + nend)>>1;    if(index<=mid)        updata(index,change,nstart,mid,rt<<1);    else        updata(index,change,mid+1,nend,rt<<1|1);    //从底向上进行更新    tt[rt].maxx = max(tt[rt<<1].maxx,tt[rt<<1|1].maxx);    tt[rt].minn = min(tt[rt<<1].minn,tt[rt<<1|1].minn);}int main(){    int t;    scanf("%d",&t);    while(t--){        int k;        scanf("%d",&k);        k = 1<<k;        memset(xx,0,sizeof(xx));        for(int i = 0;i<k;i++)            scanf("%d",&xx[i]);        build(0,k-1,1);        int m;        scanf("%d",&m);        while(m--){            int c,a,b;            scanf("%d%d%d",&c,&a,&b);            if(c==1){                long long m = query_max(a,b,0,k-1,1);                long long M = query_min(a,b,0,k-1,1);                 /*                              第一种情况:如果最大值都小于0,那个最小值为最大值*最大值                    第二种情况:如果最小值都大于0,那个最小值为最小值*最小值                    第三种情况:最小值为最大值*最小值                */                if(m<0)                    printf("%lld\n",m*m);                else if(M>0)                    printf("%lld\n",M*M);                else                    printf("%lld\n",M*m);            }            else                updata(a,b,0,k-1,1);        }    }    return 0;}
阅读全文
0 0
原创粉丝点击