【日常练习 线段树】HDU1754 I hate it

IHateIt I H a t e I t


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

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


Input
本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N<0,200000> 和 M<0,5000> 分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取’Q’或’U’) ,和两个正整数A,B。
当C为’Q’的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为’U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。


Output
对于每一次询问操作,在一行里面输出最高成绩。

Sample Input
5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5


Sample Output
5
6
5
9


HintHuge input,the C function scanf() will work better than cin

思路:线段树的区间查找最大值和单点更新。

开始的时候想都没想直接暴力刚 TLE得理所当然,询问和单点更新交替操作不爆掉才怪。。。第一次上手用一发线段树


#include<bits/stdc++.h>
using namespace std;
const int Maxi = 5416452;

int segTree[4*Maxi+10];

void PushUpNode(int node){
    segTree[node]=max(segTree[node<<1],segTree[node<<1|1]);
}

void bulid(int begin,int end,int node){
     if(begin==end){
        scanf("%d",&segTree[node]);
        return ;
     }
     int mid = (begin+end)>>1;
     bulid(begin,mid,node<<1);
     bulid(mid+1,end,node<<1|1);
     PushUpNode(node);
}
void updatedata(int p,int sc,int left,int right,int node) {
    if (left==right) {
        segTree[node] = sc;
        return ;
    }
    int mid = (left + right)>>1;
    if (p <= m) updatedata(p , sc , left, mid, node<<1);
    else updatedata(p,sc,mid+1, right,node<<1|1);
    PushUpNode(node);
}

int query(int begin,int end,int left,int right,int node){ 

    if(begin<=left&&right<=end){
        return segTree[node];
    }
    int mid =(left+right)>>1;
    int ret = 0;
    if(begin<=mid){
        ret = max(ret,query(begin,end,left,mid,node<<1));
    }
    if(mid<end){
        ret = max(ret,query(begin,end,mid+1,right,node<<1|1)); 
    }
    return ret;   
} 

int main(){
    int n , m;
    while (~scanf("%d%d",&n,&m)) {
        bulid(1 , n , 1);
        while (m --) {
            char op[2];
            int a , b;
            scanf("%s%d%d",op,&a,&b);
            if (op[0] == 'Q') printf("%d\n",query(a , b , 1 , n , 1));
            else updatedata(a , b , 1 , n , 1);
        }
    }return 0;
}

在学习线段树的过程中,窝觉得低层节点大概就是mm个的样子那数组只要开2*mm-1就好了啊。。对开 *4的空间很是费解。。然后神犇甩给窝的链接也还是不求甚解。。点这里。。。4倍空间的解释
然后神犇又告诉窝其实线段树是可以开二倍空间的!在构造树的时候有好多节点并没有用得上
比如下面代码运行起来之后。。

#include<bits/stdc++.h>
using namespace std;
const int maxi = 1213213;
int segTree[maxi*4+10];
int array[maxi];
void PushUp(int node){
    segTree[node]=max(segTree[node<<1],segTree[node<<1|1]);
}
void bulid(int left ,int right,int node){
    if(left==right){
        segTree[node]=array[left];
        return;
    }
    int mid = (left+right)>>1;
    bulid(left,mid,node<<1);
    bulid(mid+1,right,node<<1|1);
    PushUp(node);
}
int main(){
    array[1]=1,array[2]=2,array[3]=2,array[4]=4,array[5]=1,array[6]=3;
    bulid(1,6,1);
    for(int i = 1;i<=13;i++){
        cout<<"segTree"<<i<<" "<<segTree[i]<<endl;
    }return 0;
}


显然NODE10和11是没有用到。。所以有没有一种方法,能直接把线段树所有的节点,恰好对应到n个连续空间上?
留待更新…

int ID(int l,int r){
    return l+r|l!=r;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值