HDU 1166 解题报告 线段树

这是一题线段树的入门题,主要是点更新。

编码用的是完全二叉树,即数组,用链表会超时。其次用 p << 1 这样的位操作能省下200ms 左右。

#include 

#define maxn 50000
//4倍大小是一个合适的值
int ns[maxn * 4 + 100];
int nums[maxn]; //完全二叉树存储区间树

void build(int p, int l, int r)
{
	if (l == r) {
		ns[p] = nums[l-1];
	}
	else {
		int mid = (l + r) / 2;
		build((p<<1), l, mid);
		build((p<<1)+1, mid+1, r);
		ns[p] = ns[(p<<1)] + ns[(p<<1)+1];
	}
}

void add(int p, int l, int r, int n, int num)
{
	if (l == r) {
		ns[p] += num;
	}
	else {
		int mid = (l + r) / 2;
		if (n <= mid) add((p<<1), l, mid, n, num);
		else add((p<<1)+1, mid+1, r, n, num);
		ns[p] = ns[(p<<1)] + ns[(p<<1)+1];
	}
}

void sub(int p, int l, int r, int n, int num)
{
	if (l == r) {
		ns[p] -= num;
	}
	else {
		int mid = (l + r) / 2;
		if (n <= mid) sub((p<<1), l, mid, n, num);
		else sub((p<<1)+1, mid+1, r, n, num);
		ns[p] = ns[(p<<1)] + ns[(p<<1)+1];
	}
}

int query(int p, int l, int r, int ll, int rr)
{
	if (l == ll && r == rr) {return ns[p];}
	else {
		int mid = (l + r) / 2;
		if (rr <= mid) {return query((p<<1), l, mid, ll, rr);}
		else if (mid < ll) {return query((p<<1)+1, mid+1, r, ll, rr);}
		else {return query((p<<1), l, mid, ll, mid) + query((p<<1)+1, mid+1, r, mid+1, rr);}
	}
}

int main()
{
	//freopen("testdata/1166.txt", "r", stdin);
	int t, n, id, num, Case = 1;
	char input[30], opera[10];
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		for (int i = 0; i < n; ++i) scanf("%d", &nums[i]);
		build(1, 1, n);
		printf("Case %d:\n", Case++);
		getchar();
		while (fgets(input, sizeof(input), stdin)) {
			if (input[0] == 'E') break;
			sscanf(input, "%s %d %d", opera, &id, &num);
			if (opera[0] == 'Q') {
				printf("%d\n", query(1, 1, n, id, num));
			}
			else if (opera[0] == 'A') {
				add(1, 1, n, id, num);
			}
			else if (opera[0] == 'S') {
				sub(1, 1, n, id, num);
			}
		}
	}
	return 0;
}


你可能感兴趣的:(hdu,ACM)