您的位置:首页 > 其它

线段树

2015-08-18 19:02 204 查看
  题意:假设整个货架上从左到右摆放了N种商品,并且依次标号为1到N,每次给出一段区间[L, R],要做的是选出标号在这个区间内的所有商品重量最轻的一种,并且告诉这个商品的重量。但是在这个过程中,可能会因为其他人的各种行为,对某些位置上的商品的重量产生改变(如更换了其他种类的商品)。

  线段树求区间元素的性质的题目。线段树使用数组来实现完全二叉树的结构,下标从1开始,一个结点i的左孩子为2*i,右孩子为2*i+1。假设父结点的区间范围为[l,r],则左孩子的区间范围为:[l,mid];右孩子的区间范围为:[mid+1,r]。下面给出实现代码。

#include<cstdio>
#include<cstring>
using namespace std;

#define M 100000005
struct Node{
int l, r, min;
};

Node nodes[M];
int arr[M];

int min(int a, int b){
return a < b ? a : b;
}

void buildTree(int l, int r, int i){
nodes[i].l = l;
nodes[i].r = r;
if (l == r){
nodes[i].min = arr[l];
return;
}
int mid = (l + r) >> 1;
buildTree(l, mid, 2 * i);
buildTree(mid + 1, r, 2 * i + 1);
nodes[i].min = min(nodes[2 * i].min, nodes[2 * i + 1].min);
}

void update(int id, int price, int i){
if (nodes[i].l == nodes[i].r){
nodes[i].min = price;
return;
}
int mid = (nodes[i].l + nodes[i].r) >> 1;
if (id <= mid){
update(id, price, i * 2);
}
else{
update(id, price, i * 2 + 1);
}
nodes[i].min = min(nodes[i * 2].min, nodes[i * 2 + 1].min); //!!!
}

int query(int l, int r, int i){
if (l == nodes[i].l && r == nodes[i].r)
return nodes[i].min;
int mid = (nodes[i].l + nodes[i].r) >> 1;
if (r <= mid){ // 在左子树中
return query(l, r, 2 * i);
}
else if (l > mid){
return query(l, r, 2 * i + 1);
}
else{
return min(query(l, mid, 2 * i), query(mid + 1, r, 2 * i + 1));
}
}

int main(){
int m, n, f, l, r, id, price;
while (scanf("%d", &n) != EOF){
for (int i = 1; i <= n; ++i){
scanf("%d", &arr[i]);
}
buildTree(1, n, 1);
scanf("%d", &m);
while (m--){
scanf("%d", &f);
if (f == 1){
scanf("%d%d", &id, &price);
update(id, price, 1);
}
else{
scanf("%d%d", &l, &r);
printf("%d\n", query(l, r, 1));
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: