hdu4027题解——线段树

hdu4027题解——线段树

题意:
n个数,m次询问:
0 l r :将[l, r]内的数取根号并向下取整。
1 l r :输出[l, r]区间和。
思路:线段树,维护区间和。
坑点:l 可能会大于 r,需要剪枝,否则直接TLE,当值为1时不需要再取根号了,剪枝后500ms左右。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const int MAXN = 4 * N;
struct node
{
	ll l, r, val;
}t[MAXN];
ll a[N];

void pushup(ll n)
{
	t[n].val = t[n * 2].val + t[n * 2 + 1].val; 
}

void build(ll n, ll l, ll r)
{
	t[n].l = l;
	t[n].r = r;
	if(l == r)
	{
		t[n].val = a[l];
		return;
	}
	ll mid = (l + r) / 2;
	build(n * 2, l, mid);
	build(n * 2 + 1, mid + 1, r);
	pushup(n);
}
void update(ll  n, ll  L, ll  R)//区间更新
{
	ll l = t[n].l, r = t[n].r;
	if(t[n].val == (r - l + 1)) return;//剪枝很重要,但结点为1是不需要再取根号 
	if(l == r) {
		t[n].val = (ll)sqrt(t[n].val);
		return ;
	}
	ll mid = (l + r) / 2;
	if(L <= mid) update(n * 2, L, R);
	if(R > mid) update(n * 2 + 1, L, R);
	pushup(n);
}

void update(ll n, ll pos)//单点更新
{
	ll l = t[n].l, r = t[n].r;
	if(l == r)
	{
		t[n].val++;
		return ;
	}
	ll mid = (l + r) / 2;
	if(pos <= mid) update(n * 2, pos);
	else update(n * 2 + 1, pos);
	pushup(n);
}

ll query(ll n, ll L, ll R)//区间查询
{
	ll l = t[n].l, r = t[n].r;
	if(L <= l && R >= r) 
	{
		return t[n].val;
	}
	if(l == r) return 0;
	ll mid = (l + r) / 2, ans = 0;
	if(L <= mid)  ans += query(n * 2, L, R);
	if(mid < R) ans += query(n * 2 + 1, L, R);
	return ans; 
} 
int main()
{
	ll n, m, c = 1;
	while (scanf("%lld", &n) != EOF)
	{
		for (ll i = 1; i <= n; i++)
			scanf("%lld", &a[i]);
		build(1, 1, n);
		scanf("%lld", &m);
		ll op, l, r;
		printf("Case #%lld:\n", c++);
		for (ll i = 1; i <= m; i++)
		{
			scanf("%lld %lld %lld", &op, &l, &r);
			if(l > r) swap(l, r);
			if(op)
			{
				printf("%lld\n", query(1, l, r));
			}
			else
			{
				update(1, l, r);
			}
		}
		printf("\n");
	}
}
发布了26 篇原创文章 · 获赞 2 · 访问量 426

猜你喜欢

转载自blog.csdn.net/D_Bamboo_/article/details/100548730