线段树

好久没做算法题了,今天做了一道,又是百度又是思考的,忙活了大半天(半天多),终于把它 AC 了。我去,看来真是忘得差不多了。

这是一道最基础的线段树。当然,这道题也可以用树状数组来做。

就当是复习一下线段树了。

线段树是这样一棵树,它是一棵二叉树,每个树的节点是一个区间,他的两个孩子节点的区间正好平分他。还可能保存有其他数据,比如说这个区间内的和。树一般用指针来表示,但是线段树大多用结构体数组来实现二叉树(听说是因为用数组比指针快)。一个下标为 i(从 1 开始) 的节点,它的左孩子节点下标为 2 * i;右孩子节点下标为 2 * i + 1。这样,就可以完美的构造一颗线段树了。

本题很简单,题意就是给一个数字序列 A1-An,然后很多询问,每个询问只有两种,一个更新某一个(Ai)数据,一个查询从 Am - An 中谁的值最大。怎么样,很简单吧。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MAX 1000010

typedef struct node{
	int l;
	int r;
	int value;
}Node;

int father[ MAX ];
int A[ MAX ];
Node nodes[ MAX ];

void build(int l,int r,int i){
	nodes[ i ].l = l;
	nodes[ i ].r = r;
	nodes[ i ].value = 0;

	if(l == r){
		father[ l ] = i;
		nodes[ i ].value = A[ l ];
		while(i != 0){
			if(nodes[ i / 2 ].value < nodes[ i ].value)
			nodes[ i / 2 ].value = nodes[ i ].value;
			i /= 2;
		}
		return;
	}
	build(l, (int)floor((l + r)/2.0), i * 2);
	build((int)floor((l + r)/2.0) + 1, r, i * 2 + 1);
}

void Query(int l,int r,int i,int * x){
	if(nodes[i].l==l && nodes[i].r==r){
		(*x)=((*x) < nodes[i].value) ? nodes[i].value : (*x);
		return ;
	}

	i = i<<1;
	if(l <= nodes[i].r){
		if(r<=nodes[i].r)
			Query(l,r,i,x);
		else
			Query(l,nodes[i].r,i,x);
	}

	i+=1;
	if(r>=nodes[i].l)
		if(l>=nodes[i].l)
			Query(l,r,i,x);
		else
			Query(nodes[i].l,r,i,x);
}

void Update(int x){
	int y,a,b;
	if(x == 1) return;
	y = x / 2;
	a=nodes[y<<1].value;
	b=nodes[(y<<1)+1].value;
	nodes[y].value = (a>b)?a:b;
	Update(x/2);
}

int main()
{
	int i,SN,QN,m,n;
	int *x=(int *)malloc(sizeof(int));
	char s[10];
	while(scanf("%d%d",&SN,&QN)!=EOF){
		for(i=1; i<=SN; i ++){
			scanf("%d",&A[i]);
		}
		build(1,SN,1);
		for(i=0;i<QN;i++){
			(*x) = 0;
			scanf("%s%d%d",s,&m,&n);
			if(s[0]=='Q'){
				Query(m,n,1,x);
				printf("%d\n",(*x));
			}
			if(s[0]=='U'){
				nodes[father[m]].value = n;
				Update(father[m]);
			}
		}
	}
}

参考了很多线段树代码,勉强给写出来了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值