HDU 4893 线段树延迟标记

原题链接

题意


  • 初始有一长度为n,全为0的序列

  • 每次我们可以对这个序列进行三种操作:

    • 1.将某个位置的数加上d

    • 2.输出某个区间的和

    • 3.将某个区间内每个数字变为与其最接近的斐波那契数,如果有两个最相近的数,则取更小的那个。

思路


  • 首先对于寻找最近的斐波那契数,我们可以预处理一个90+大小的数组来保存斐波那契数列的前90项,此时范围其实已经要覆盖long long了,完全够用,可以用lower_bound来查询

  • 然后就是这个区间和可以用线段树保存,对于区间的3操作,肯定是不能一个一个去操作的,所以我们可以想到在操作前我们就保存好这个区间的“斐波那契和”。

  • 这样的话,对于每次单点修改操作,我们都要更新一遍线段树路径上的区间和与“斐波那契和”,可以发现,题目中没有区间加和修改的操作,正是我们这种方法得以实行的原因——每次只需要更新一条路上的数据。然后我们使用lazy标记确保3操作的时间复杂度即可。

AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

struct ab
{
	long long v;
	long long fv;
	bool fl;
} aa[400005];
int n, m, co = 0;

long long fb[1005];

long long abss(long long a)
{
	if (a < 0)
	{
		a = -a;
	}
	return a;
}

void build(int o, int l, int r)
{
	aa[o].fl = false;
	if (l == r)
	{
		aa[o].v = 0;
		aa[o].fv = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(o << 1, l, mid);
	build(o << 1 | 1, mid + 1, r);
	aa[o].v = aa[o << 1].v + aa[o << 1 | 1].v;
	aa[o].fv = aa[o << 1].fv + aa[o << 1 | 1].fv;
}

void pd(int o)
{
	if (aa[o].fl)
	{
		aa[o].fl = false;
		aa[o << 1].v = aa[o << 1].fv;
		aa[o << 1].fl = true;
		aa[o << 1 | 1].v = aa[o << 1 | 1].fv;
		aa[o << 1 | 1].fl = true;
	}
}

void update(int o, int l, int r, int k, long long x)
{
	if (l == r)
	{
		aa[o].v += x;
		int ll = lower_bound(fb, fb + 91, aa[o].v) - fb;
		if (!ll)
		{
			aa[o].fv = 1;
		}
		else if (abss(fb[ll] - aa[o].v) < abss(fb[ll - 1] - aa[o].v))
		{
			aa[o].fv = fb[ll];
		}
		else
		{
			aa[o].fv = fb[ll - 1];
		}
		return;
	}
	pd(o);
	int mid = (l + r) >> 1;
	if (l <= k && mid >= k)
	{
		update(o << 1, l, mid, k, x);
	}
	if (mid < k && r >= k)
	{
		update(o << 1 | 1, mid + 1, r, k, x);
	}
	aa[o].v = aa[o << 1].v + aa[o << 1 | 1].v;
	aa[o].fv = aa[o << 1].fv + aa[o << 1 | 1].fv;
}

void change(int o, int l, int r, int x, int y)
{
	if (x <= l && y >= r)
	{
		aa[o].fl = true;
		aa[o].v = aa[o].fv;
		return;
	}
	pd(o);
	int mid = (l + r) >> 1;
	if (x <= mid)
	{
		change(o << 1, l, mid, x, y);
	}
	if (y > mid)
	{
		change(o << 1 | 1, mid + 1, r, x, y);
	}
	aa[o].v = aa[o << 1].v + aa[o << 1 | 1].v;
	aa[o].fv = aa[o << 1].fv + aa[o << 1 | 1].fv;
}

long long qu(int o, int l, int r, int x, int y)
{
	if (l >= x && r <= y)
	{
		return aa[o].v;
	}
	pd(o);
	int mid = (l + r) >> 1;
	long long ans1 = 0, ans2 = 0;
	if (x <= mid)
	{
		ans1 = qu(o << 1, l, mid, x, y);
	}
	if (y > mid)
	{
		ans2 = qu(o << 1 | 1, mid + 1, r, x, y);
	}
	return ans1 + ans2;
}

int main()
{
	fb[1] = fb[0] = 1;
	for (int i = 2; i <= 90; ++i)
	{
		fb[i] = fb[i - 2] + fb[i - 1];
	}
	while (scanf("%d%d", &n, &m) == 2)
	{
		build(1, 1, n);
		for (int i = 1; i <= m; ++i)
		{
			int q, l, r;
			scanf("%d", &q);
			if (q == 1)
			{
				int t;
				long long xx;
				scanf("%d%lld", &t, &xx);
				update(1, 1, n, t, xx);
			}
			else if (q == 2)
			{
				scanf("%d%d", &l, &r);
				printf("%lld\n", qu(1, 1, n, l, r));
			}
			else
			{
				scanf("%d%d", &l, &r);
				change(1, 1, n, l, r);
			}
		}
	}
	return 0;
}

posted @ 2021-01-25 20:16  _int_me  阅读(119)  评论(0编辑  收藏  举报