I Hate It【线段树 最值】

I Hate It
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 86070 Accepted Submission(s): 33036

Problem Description
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。

不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。

Input
本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0

#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--)

const int maxnode =1<<19; //2的19 次方 
const int maxx =2e6+10;

struct act{
    int value;
    int left,right;
}node[maxnode];//所有的节点


int father[maxx];

void buildtree(int i,int left,int right){
    node[i].left=left;
    node[i].right=right;
    node[i].value= 0;
    if(left==right){ father[left]=i;return ;}

    buildtree(i<<1,left,(int)(floor(left+right)/2.0)); //向左进行循环 
    buildtree((i<<1)+1,(int)(floor(left+right)/2.0)+1,right);//向右进行循环 
}

void updatetree(int ri){ //更新区间的 最大值 
    if(ri==1) return ;
    int fi=ri/2; //临时处理该节点下的 两个儿子的 最大值 并赋值给 该点的 value 
    int a=node[fi<<1].value; //左儿子vaule  
    int b=node[(fi<<1)+1].value; // 右儿子的 value 
    node[fi].value=max(a,b);  //将两个儿子的 value 赋值给 该节点的 最大值 
    updatetree(ri/2); //向上更新 
}
int Max;

void query(int i,int l,int r){ //查询区间的最大值 
    if(node[i].left==l&&node[i].right==r){ //如果要查询的区间就是 该区间 就进行更新最大值 
        Max=max(Max,node[i].value);  //将划分的几个区间 都进行一个 最大值的筛选 
        return ; //结束该层递归 
    }
    i=i<<1; //i的2次方 该节点的 左儿子 
    if(l<=node[i].right){ //左区间 在 当前节点的 右区间的左边  说明右交集 
        if(r<=node[i].right) query(i,l,r); //继续进行 递归 并且r在right的 左边就进行 l r的递归求解 
        else query(i,l,node[i].right); //如果r大于该节点的右边界 下一次递归就进行 l 到 最大的右区间的位置 
    }

    i++; //该节点的右儿子 
    if(r>=node[i].left){ //如果需要查询的右区间 大于该点的右区间 
        if(l>=node[i].left) query(i,l,r);//并且需要查询的左区间 大于该点的左区间 那么久进行 l r的查询 
        else query(i,node[i].left,r); //否则 就进行该区间的向下的递归 
    } 
}
int main(){
    int n,m,q;
    ios::sync_with_stdio(false);
    while(cin>>n>>m){
        buildtree(1,1,n);//建树
        ERD(i,1,n){
            cin>>q;
            node[father[i]].value=q;
            updatetree(father[i]);
        }
        string op;
        int a,b;
        while(m--){
            cin>>op>>a>>b;
            if(op[0]=='Q'){
                Max=0;
                query(1,a,b);//查询该区间的最大值
                cout<<Max<<endl;
            }
            else{
                node[father[a]].value=b;//该点的值等于 value
                updatetree(father[a]);//并进行更新 最大值  该函数的作用就是 将区间中的最大值 赋给每个区间 就是该区间的最大值 
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值