最大最小值【线段树 c】

时间限制:1000 ms | 内存限制:65535 KB
难度:2

描述
给出N个整数,执行M次询问。
对于每次询问,首先输入三个整数C、L、R:
如果C等于1,输出第L个数到第R个数之间的最小值;
如果C等于2,输出第L个数到第R个数之间的最大值;
如果C等于3,输出第L个数到第R个数之间的最小值与最大值的和。
(包括第L个数和第R个数)。

输入
首先输入一个整数T(T≤100),表示有T组数据。
对于每组数据,先输入一个整数N(1≤N≤10000),表示有N个整数;
接下来一行有N个整数a(1≤a≤10000);
然后输入一个整数M,表示有M次询问;
接下来有M行(1≤M≤10000),每行有3个整数C、L、R(1≤C≤3,1≤L≤R≤N)。
输出
按照题意描述输出。每个输出占一行。
样例输入
2
4
1 3 2 4
2
1 1 4
2 2 3
5
1 2 3 4 5
1
3 1 5
样例输出
1
3
6

#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<iomanip>
using namespace std;
typedef int _____I;
const int N=1e6+10;
const int INF=0x3f3f3f3f;
#define ERX(___I,__I,_I) for(_____I ___I = __I;___I <  _I; ___I++)
#define ERD(___I,__I,_I) for(_____I ___I = __I;___I <= _I; ___I++)
#define RED(___I,__I,_I) for(_____I ___I = __I;___I >= _I; ___I--)
超时代码

/*
int t;
int n,m;
int c,l,r;
int a[10200];

int main(){
//  ios::sync_with_stdio(false);
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)   cin>>a[i];

        scanf("%d",&m);
        int x,y,z;
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&x,&y,&z);
            if(x==1){
                int minn=INF;
                for(int j=y;j<=z;j++)
                    if(minn>a[j])   minn=a[j];
                printf("%d\n",minn);
            }
            else if(x==2){
                int maxx=0;
                for(int j=y;j<=z;j++)
                    if(maxx<a[j])   maxx=a[j];
                printf("%d\n",maxx);
            }
            else {
                int maxx=0,minn=INF;
                for(int j=y;j<=z;j++){
                    if(maxx<a[j])   maxx=a[j]; 
                    if(minn>a[j])   minn=a[j];
                }
                printf("%d\n",maxx+minn);
            }
        }
    }
    return 0;
}


*/
#include<stdio.h>
int p[10000+10];
struct record{
    int left,right,max,min;
}num[100000+10];

int MAX(int x,int y){return x>y?x:y;}
int MIN(int x,int y){return x<y?x:y;}

int buildmin(int left,int right,int node){ //从节点1 赋值为整个区间  然后以此分两半给其左右子树 

    int mid;

    num[node].left=left; //对该节点 进行左右区间的赋值 
    num[node].right=right;

    if(left==right)     return num[node].min=p[left]; //如果说该区间的   叶子节点   最后的叶子节点 分布为 1-n  因此该语句会执行n次 

    mid=(left+right)>>1;  //进行左右子树的 遍历 

    return num[node].min=MIN(buildmin(left,mid,node*2),buildmin(mid+1,right,node*2+1)); //返回 将节点的最小值取 下一个 mid的 左区间到 mid 节点为 node*2 右区间为 mid+1 到 right 节点为 node*2+1 
}
int buildmax(int left,int right,int node){ //每一个区间的最大值 赋值给了该区间 

    int mid;

    num[node].left=left;
    num[node].right=right;

    if(left==right) return num[node].max=p[left]; //如果说到了 叶子节点 就将该节点的 最大值给 该数组

    mid=(left+right)>>1;//2
    return num[node].max=MAX(buildmax(left,mid,node*2),buildmax(mid+1,right,node*2+1));
}
int querymin(int left,int right,int node){//求最小值 

    int mid;
    if(num[node].left==left&&num[node].right==right)    return num[node].min;  //如果二分的找到了该区间 就将该区间的最小值 返回 

    mid=(num[node].left+num[node].right)>>1; //该节点的左右区间 二分向下 

    if(right<=mid)  return querymin(left,right,node*2);// 如果要找到的区间的 左端 小于等于 二分出来的mid的话 就进行原本区间的递归查询 

    else{  //否则right 大于 mid 的话 就进行 判断  
        if(left>mid)    return querymin(left,right,node*2+1); //如果left大于mid  就进行 原本区间的递归 
        else    return MIN(querymin(left,mid,node*2),querymin(mid+1,right,node*2+1));//除了上面两种情况  就剩该情况了  
    }
}

//1.______left_____right___mid_____________________________  querymin(left,right,node*2);   基于准确区间的查询 
//2._______________________mid___left_______right__________  querymin(left,right,node*2+1);  同上 
//3._____________left______mid______right__________________  MIN(querymin(left,mid,node*2),querymin(mid+1,right,node*2+1)); 基于两个区间的 查询 最后只用返回一个 两中情况的最优 


int querymax(int left,int right,int node){//求最大值 
    int mid;

    if(num[node].left==left&&num[node].right==right)return num[node].max;

    mid=(num[node].left+num[node].right)>>1;

    if(right<=mid)  return querymax(left,right,node*2);
    else{
        if(left>mid)    return querymax(left,right,node*2+1);
        else    return MAX(querymax(left,mid,node*2),querymax(mid+1,right,node*2+1));
    }
}
int main(){
    int t,n,m,i,j;
    int a,b,c;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);

        for(i=1;i<=n;i++)   scanf("%d",&p[i]);
        buildmin(1,n,1); //建树 
        buildmax(1,n,1); //建树 
        //得到每个区间的 最大 最小值 

        scanf("%d",&m);//输入m个数据 
        while(m--){
            scanf("%d%d%d",&a,&b,&c); //输入 操作数 
            if(a==1)    printf("%d\n",querymin(b,c,1)); //得到最小的 值 从 b到c区间  从节点为一的 
            if(a==2)    printf("%d\n",querymax(b,c,1)); //返回最大值 在 b c 区间的 
            if(a==3)    printf("%d\n",querymin(b,c,1)+querymax(b,c,1));
        }
    }
    return 0;
} 


/*

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include <fstream>
#include <limits>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cassert>
using namespace std;
struct la{
    int w;
    int z;
}a[10000+10];

bool cmp(la x,la y){return x.z<y.z;}


int main(){
    int t,T,i,j,k,n,c,l,r;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(i=1;i<=n;i++){
            scanf("%d",&a[i].z);
            a[i].w=i;
        }
        sort(a+1,a+n+1,cmp);

        scanf("%d",&T);
        while(T--){
            scanf("%d %d %d",&c,&l,&r);
            int da=0;
            if(c==1||c==3)
                for(i=1;i<=n;i++){
                    if(a[i].w<=r&&a[i].w>=l){
                        da+=a[i].z;
                        break;
                    }
                }
            if(c==2||c==3)
                for(i=n;i>=1;i--){
                    if(a[i].w<=r&&a[i].w>=l){
                        da+=a[i].z;
                        break;
                    }
                }
            printf("%d\n",da);
        }
    }
    return 0;
}*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值