现在的位置: 首页 > 综合 > 正文

hdu1166 线段树

2013年12月07日 ⁄ 综合 ⁄ 共 2643字 ⁄ 字号 评论关闭

线段树就是区间的查找,如果区间不是当前线段树节点的区间,需要划分为左、右,再递归查找

#include <iostream>
#include <stdio.h>
#include <string>

using namespace std;

const int maxn = 55555;
int a[maxn];
int tree[maxn << 2];//节点数是区间的4倍

void pushUp(int curr) {
    tree[curr] = tree[2*curr] + tree[2*curr+1];
}

void buidTree(int left, int right, int curr) {//本节点在数组中的位置是curr;本节点的左边界是left,右边界是right
    if (left == right) {
        tree[curr] = a[left];
        return;
    }

    int m = left + (right - left)/2;
   // if (m >= left)
        buidTree(left,m,2*curr);
   // if (m+1<=right)
        buidTree(m+1,right,2*curr + 1);

    pushUp(curr);

}

void update(int p, int add, int left, int right, int curr) {//第p个数,增加add;当前节点是curr,左是left,右是right;先找到p在哪个范围内,一定要找到精确的小范围,然后大范围是由小范围组合而成
    if (left == right) {
        tree[curr] += add;
        return;
    }

    int m = left + (right - left)/2;
    if (p <= m)
        update(p,add,left,m,2*curr);
    else
        update(p,add,m+1,right,2*curr + 1);

    pushUp(curr);

}

int query(int ql, int qr, int currLeft, int currRight, int curr) {//查找区间[ql,qr]
    if (ql <= currLeft && qr >= currRight) {
        return tree[curr];
    }
    int m = currLeft + (currRight - currLeft)/2;
    int sum = 0;
    if (ql <=m)
        sum = query(ql,qr,currLeft,m,2*curr);
    if (qr >m)
        sum += query(ql,qr,m+1,currRight,2*curr+1);
    
    return sum;
}

int main() {
    int t,n;
    scanf("%d", &t);
    for (int i = 0; i < t ; ++i ) {
        printf("Case %d:\n",i+1);
        scanf("%d",&n);
        memset(a,0,sizeof(a));
        for (int j = 1; j <= n; ++j )
            scanf("%d",a + j);
        
        buidTree(1,n,1);

        char op[10];
        while(scanf("%s",&op)) {
            if (op[0] == 'E')
                break;
            int a1,a2;
            scanf("%d%d",&a1,&a2);
            if (op[0] == 'Q')
                printf("%d\n",query(a1,a2,1,n,1));
            else if(op[0] == 'S')
                update(a1,-a2,1,n,1);
            else
                update(a1,a2,1,n,1);

        }

    }
}

#include <iostream>
#include <stdio.h>

using namespace std;

const int maxn = 55555;
int a[maxn];
int tree[maxn<<2];//线段树的每一个叶子节点就是a中的元素,还有其他的非叶子节点,应该需要2*maxn+1个元素

void pushUp(int ind) {
	tree[ind] = tree[2*ind] + tree[2*ind+1];
}

void buildTree(int left, int right, int ind) {//找到叶子节点相应的位置, ind是这个节点的编号//left 和 right是这个节点所对应的范围
	if (left == right) {
		tree[ind] = a[left];
		return;
	}

	int mid = (left + right)/2;
	buildTree(left, mid, 2*ind);
	buildTree(mid+1, right, 2*ind + 1);
	pushUp(ind);

}

int query(int beg, int end , int left, int right, int ind){// beg, end是要查询的区间;left和right是这个节点的范围
	if (beg<=left && end >= right)
		return tree[ind];
	int mid = (left + right) / 2;
	int l = 0, r = 0;
	if (mid >= beg)
		l = query(beg,end,left,mid, 2*ind);
	if (mid < end)
		r = query(beg,end,mid +1,right, 2*ind+1);
	return l+ r;
}


void update(int pos, int value, int left, int right, int ind) {
	if(left == right) {
		tree[ind] += value;
		return;
	}

	int mid = (left + right) / 2;
	if (mid >=pos)
		update(pos, value, left, mid, 2*ind);
	else
		update(pos,value, mid + 1, right, 2*ind+1);

	pushUp(ind);
}


int main() {
	int t,n;
	scanf("%d", &t);

	for (int i = 0; i < t ; ++i)
	{
		printf("Case %d:\n", i + 1);
		scanf("%d", &n);
		memset(a,0,sizeof(a));
		for(int j = 1; j <= n; ++j)
			scanf("%d", a + j);

		buildTree(1,n, 1);

		char op[10];
		while (scanf("%s", op)){
			if (op[0] == 'E')
				break;
			int a1, a2;
			scanf("%d%d", &a1,&a2);
			if (op[0] == 'Q')
				printf("%d\n", query(a1, a2,1,n,1));
			else if(op[0] == 'S')
				update(a1,-a2,1,n,1);
			else
				update(a1,a2,1,n,1);

		}
	}
}

抱歉!评论已关闭.