zoj3279 ants 线段树

突然想学习一下线段树了,看了一下基本的知识,尝试了一道简单的线段树题目。

#include<iostream>
#include<cstring>

using namespace std;
const int N = 100010;
struct node {
	int sum;
	int l;
	int r;
};
struct node tree[4 * N]; //树数组长度需要区间长度的 4 倍
int a[N];                //level即区间 

void build(int t, int l, int r) { //建树,这里用数组存放树,类似的情况出现在堆排序中,节点 i 的左节点为 2*i,右节点 2*i + 1
	tree[t].l = l;                
	tree[t].r = r;      //根节点区间为 0-n,左子节点区间 0- n/2, 右子节点区间 n/2 - n, 左闭右开;
	if (l == r - 1) {   // 这里的区间 2-3(已经到叶子节点),即代表level 3, sum的数值表示此区间元素的数量
		tree[t].sum = a[l];     
		return;
	}
	int mid = (l + r) / 2;  //递归建左子树,递归建右子树,根sum的值为左右子树sun的和
	build(2 * t, l, mid);
	build(2 * t + 1, mid, r);
	tree[t].sum = tree[2 * t].sum + tree[2 * t + 1].sum;
}
void update(int t, int l, int r, int value) { //更新操作,从节点t开始更新, 将区间l-r的元素数量变为 value
	if (tree[t].l >= l && tree[t].r <= r) {  //即改变level r中的元素个数
		tree[t].sum = value;
		return;
	}
	if (tree[t].l == tree[t].r - 1)
		return;
	int mid = (tree[t].l + tree[t].r) / 2;
	if (l <= mid) //如果根节点区间的中值 >= 区间l-r的左端
		update(2 * t, l, r, value); //那么在左子树中更新
	if (r > mid) //如果根节点区间的中值 < 区间l-r的右端
		update(2 * t + 1, l, r, value); //那么右子树也需要更新
	tree[t].sum = tree[2 * t].sum + tree[2 * t + 1].sum; //左右子树更新之后,更新根节点的sum值
}

int query(int t, int len) { //给定一个排名 len, 查询其处于哪一个level
	if (tree[t].l == tree[t].r - 1) { //查找到区间, 返回level
		return tree[t].r;
	}
	if (len <= tree[2 * t].sum) //如果排名 小于左子树元素数量,区间肯定在左子树中
		return query(2 * t, len);
	else //否则,在右子树查询排名为 (len - 左子树元素数量)的区间                      
		return query(2 * t + 1, len - tree[2 * t].sum);
}

int main()
{
	int n;
	while (cin >> n) {
		for (int i = 0; i < n; ++i)
			cin >> a[i];
		memset(tree, 0, sizeof(tree));
		build(1, 0, n);
		int k;
		cin >> k;
		while (k--) {
			char type;
			cin >> type;
			if (type == 'p') {
				int level, num;
				cin >> level >> num;
				update(1, level - 1, level, num);
			}
			else {
				int len;
				cin >> len;
				cout<<query(1, len)<<endl;
			}
		}
	}


    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值