杭电OJ 1166(C++)

使用线段树模板即可。由于本题输入数据量极大,所以必须使用 scanf 输入,使用 cin 会超时。

#include <cstdio>
#include <cstring>
const int MAXN = 50005;

int tree[MAXN << 2];
int num[MAXN];
char s[7];
int L, R, C; //L,R为修改的位置,C为修改数

//更新结点信息,rt是此结点在线段树中的索引
void pushup(int rt)
{
	//结点的值等于其左子树的值加上右子树的值
	tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}

//建立线段树
void build_tree(int l, int r, int rt)
{ //l,r是区间左右端点,rt是此结点在线段树中的索引
	if (l == r) //此结点是叶子结点
	{
		tree[rt] = num[l];
		return;
	}
	int m = (l + r) >> 1;
	build_tree(l, m, rt << 1); //构造左子树
	build_tree(m + 1, r, rt << 1 | 1); //构造右子树
	pushup(rt);
}

//修改单点信息
void update(int l, int r, int rt)
{ //l,r是区间左右端点,rt是此结点在线段树中的索引
	if (l == r) //叶子结点
	{
		tree[rt] += C;
		if (tree[rt] < 0) //防止减成负数
			tree[rt] = 0;
		return;
	}
	int m = (l + r) >> 1;
	if (L <= m) //在左子树中查找
		update(l, m, rt << 1);
	else //在右子树中查找
		update(m + 1, r, rt << 1 | 1);
	pushup(rt);
}

//区间查询
int query(int l, int r, int rt)
{ //l,r是区间左右端点,rt是此结点在线段树中的索引
	if (L <= l && R >= r) //此区间被完全包含在目标区间中,返回此区间的值
		return tree[rt];
	int sum = 0;
	int m = (l + r) >> 1;
	if (L <= m) //此区间的左子树和目标区间有交集,搜索左子树
		sum += query(l, m, rt << 1);
	if (m < R) //此区间的右子树和目标区间有交集,搜索右子树
		sum += query(m + 1, r, rt << 1 | 1);
	return sum;
}

int main()
{
	int T;
	scanf("%d", &T);
	int n;
	memset(num, 0, sizeof(num));
	for (int Case = 1; Case <= T; Case++)
	{
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &num[i]);
		}
		printf("Case %d:\n", Case);
		build_tree(1, n, 1);
		while (scanf("%s", s))
		{
			if (s[0] == 'E')
				break;
			else if (s[0] == 'Q') //线段树查询
			{
				scanf("%d%d", &L, &R);
				printf("%d\n", query(1, n, 1));
			}
			else if (s[0] == 'A') //线段树点修改增加
			{
				scanf("%d%d", &L, &C);
				update(1, n, 1);
			}
			else if (s[0] == 'S') //线段树点修改减少
			{
				scanf("%d%d", &L, &C);
				C *= -1;
				update(1, n, 1);
			}
		}
	}
	return 0;
}

继续加油。

发布了138 篇原创文章 · 获赞 1 · 访问量 7033

猜你喜欢

转载自blog.csdn.net/Intelligence1028/article/details/104533835