2017 acmicpc 北京网络赛 I Minimum(线段树求区间最值)

描述
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

大致题意:告诉你2^k个数,编号从0到2^k-1,接下来有q次操作。
操作1:查询区间[l,r]内的最小乘积ax*ay,(注意x可以等于y)
操作2:将x位置上的数ax变为y

思路:用两棵线段树来分别维护区间内的最大值和最小值,假设所求的某个区间内的最大值为max,最小值为min,分析可知有如下三种情况:
1.当min>=0时,那么该区间的最小乘积即min*min
2.当max<0时,最小乘积为max*max
3.max大于0,min小于0时,最小乘积为max*min

代码如下

#include 
#include 
#include   
#include   
#include
#define lson l,m,rt<<1  
#define rson m+1,r,rt<<1|1  
using namespace std;
const int maxn=150000;
int Max[maxn<<2];
int Min[maxn<<2] ; 
int A[maxn];  
inline void PushPlus(int rt)  
{   
    Max[rt] = max(Max[rt<<1],Max[rt<<1|1]); 
    Min[rt] = min(Min[rt<<1],Min[rt<<1|1]);
}  

void Build(int l, int r, int rt)  //建树 
{  
    if(l == r)  
    {    
        Max[rt]=A[l];
        Min[rt]=A[l];
        return ;  
    }  
    int m = ( l + r )>>1;  

    Build(lson);  
    Build(rson);  
    PushPlus(rt);  
}  

void Updata(int p, int change, int l, int r, int rt)//单点更新,p位置上的数改变为change 
{  

    if(l==r)  
    {   
        Max[rt]=change;
        Min[rt]=change;
        return ;  
    }  
    int m = ( l + r ) >> 1;  
    if(p <= m)  
        Updata(p, change, lson);  
    else  
        Updata(p, change, rson);  

    PushPlus(rt);  
}  

int Query1(int L,int R,int l,int r,int rt)//求区间最大值  
{  
    if( L <= l && r <= R )  
    {  
        return Max[rt];  
    }  
    int m = ( l + r ) >> 1;  
    int ans=-1e7;  
    if(L<=m )  
        ans=max(ans,Query1(L,R,lson));  
    if(R>m)  
        ans=max(ans,Query1(L,R,rson));  

    return ans;  
}  

int Query2(int L,int R,int l,int r,int rt)//求区间最小值  
{  
    if( L <= l && r <= R )  
    {  
        return Min[rt];  
    }  
    int m = ( l + r ) >> 1;  
    int ans=1e7;  
    if(L<=m )  
        ans=min(ans,Query2(L,R,lson));  
    if(R>m)  
        ans=min(ans,Query2(L,R,rson));  

    return ans;  
}  

int main()  
{   
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int k;
        scanf("%d",&k);
        int n=1;
        while(k--)
        n*=2;

        for(int i=0;iscanf("%d",&A[i]); 

        Build(0,n-1,1);  
        int q;
        scanf("%d",&q);
        while(q--)  
        {  
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(a==1)
            {
                long long int m1=Query1(b,c,0,n-1,1);
                long long int m2=Query2(b,c,0,n-1,1);
                if(m2>=0)
                printf("%lld\n",m2*m2);
                else if(m1<=0)
                printf("%lld\n",m1*m1);
                else if(m1>=0&&m2<=0)
                printf("%lld\n",m1*m2);
            } 
            else 
            {
                Updata(b,c,0,n-1,1); 
            }   
        }  
    }

    return 0;  
}  

你可能感兴趣的:(线段树&树状数组&主席树)