(精)1754 另一种方法实现线段树(这个里面没有用到value,但是添加了一个max)

/*
1 线段树可以看做是一个很特别的二叉树
2 如果说父亲节点是n,那么两个孩子节点分别是2*n和2*n+1.这样理解很不错
*/

#include <iostream>
using namespace std;
#define MAX 600000
//#define MAX 100
struct Node
{
    int l,r,mid,max;
}node[MAX];

//获取最大值
int max(int a,int b)
{
    return a>b?a:b;
}

//初始化(其中参数n代表第几层,所以在调用的时候都写上1)
void inint(int a,int b,int n)
{
    node[n].l=a;//左边
    node[n].max=-1;//最大值,
    node[n].r=b;//右边
    node[n].mid=(a+b)/2;//中间值
    
	//如果到倒数第二层返回
    if(a+1==b)
		return;
 
	//建立左子树和右子树
    inint(a,(a+b)/2,n*2);
    inint((a+b)/2,b,2*n+1);
}

//更新(pos是学生id,value是学生的分数)(这个应该是从顶开始的,不是从低开始的)(n表示第几层)
void update(int pos,int value,int n)
{
	//如果说要插入的值,大于原来节点的最大值,那么就更新原来的值(一路上所有的点都更新了)
    if(value>node[n].max)
		node[n].max=value;
 
	//因为把这个线段树看做是左闭右开区间(所以这个条件代表达到最后一层,如果到达最后一层肯定返回)
    if((node[n].l+1)==node[n].r)
		return;

	//放入左子树
    if(pos<node[n].mid)
    {
        update(pos,value,2*n);
    }
	//放入右子树
    if(pos>=node[n].mid)
    {
        update(pos,value,2*n+1);
    }
}

//把a到为b之间的最大值找出来。n是node 的层次的值,也就是说节点的id,也就是说,调用函数的时候n==1
//同时也可以认为n就是key值,因为第一层是1,第二层是2,3,第三层是4,5,6,7
int query(int a,int b,int n)
{
	//如果说已经到了需要查找的一层
    if( node[n].l==a && node[n].r==b)
		return node[n].max;


	//如果说a<node[n].mid不一定表示在左区间
	//表示在做区间肯定有一部分在,所以应该分开计算,左区间到node[n].mid,还有就是从node[n].mid+1到b的部分
    if(a<node[n].mid)
    {
		//如果说完全在左区间
        if(b<=node[n].mid)
        {
            return query(a,b,2*n);
        }
		
		//如果左区间有一部分,右区间也有一部分
        else
        {
            return max(query(a,node[n].mid,2*n),query(node[n].mid,b,2*n+1));//后面的2*n和2*n+1代表下一个数组的层次。
        }
    }
	//如果说右区间,就进入下一个二叉树的右子树
    else
    {
        return query(a,b,2*n+1);
    }
}
    
int main()
{
	//freopen("in.txt","r",stdin);
    int n,m,t,a,b,i;
    char ch;
    while(cin >>n>>m)
    {
		//初始化
        inint(1,n+1,1);
		//输入n个学生的成绩
        for(i=1;i<=n;i++)
        {
			scanf("%d",&t);
            update(i,t,1);
        }
            
		//开始查询
        for(i=1;i<=m;i++)
        {
			getchar();
            cin >>ch;
			//输入a和b的(左右区间)
            cin >>a>>b;
			
			//如果说是查询的话
            if(ch=='Q')
				cout <<query(a,b+1,1)<<endl;//注意是b+1而不是b。因为线段树是一个左开右闭的的区间。

			//如果说是更新的话
            else
				update(a,b,1);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值