首页 > 编程语言 >从零开始学算法/C++/第三天

从零开始学算法/C++/第三天

时间:2024-06-15 22:11:39浏览次数:21  
标签:www 标记 int C++ 算法 从零开始 long P3870 com

懒标记好简单,原理就是使变化的叠加尽可能远离叶子节点,
也就是说从叶子节点往根节点走,这条路径上最多只有一个地方有懒标记 ,要将这个懒标记尽可能远离叶子节点,拖延症了属于是,这样显然时间复杂度相较不用懒标记的要低很多。
算法竞赛进阶指南里面称懒标记为延迟标记,这两种称呼都很好。
今天做了两道题[https://www.acwing.com/problem/content/244/](AcWing 243 一个简单的整数问题2)/[https://www.luogu.com.cn/problem/P3870](P3870 [TJOI2009] 开关)
整数问题琢磨了一会儿,主要在于变化函数和查询函数都要下传懒标记,已经想明白了(原理就是本博客的第二行),后面写洛谷的题十分钟秒了。


一个简单的整数问题2 https://www.acwing.com/problem/content/244/

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 1;
long long w[N];
struct node
{
	int l, r;
	long long sum, add;
}t[N << 2];
void build(int p, int l, int r)
{
	t[p] = { l,r };
	if (l == r) { t[p] = { l,l,w[l],0 }; return; }
	int mid = l + r >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
	t[p].sum = t[p << 1].sum + t[p << 1 | 1].sum;
}
void lyy(int p)
{
	if (t[p].add)
	{
		t[p << 1].add += t[p].add;
		t[p << 1 | 1].add += t[p].add;
		t[p << 1].sum += t[p].add * (t[p << 1].r - t[p << 1].l + 1);
		t[p << 1 | 1].sum += t[p].add * (t[p << 1 | 1].r - t[p << 1 | 1].l + 1);
		t[p].add = 0;
	}
}
void modify(int p, int l, int r, long long d)
{
	if (l <= t[p].l && t[p].r <= r)
	{
		t[p].sum += d * (t[p].r - t[p].l + 1);
		t[p].add += d;
		return;
	}
	lyy(p);
	int mid = t[p].l + t[p].r >> 1;
	if (l <= mid)modify(p << 1, l, r, d);
	if (r > mid)modify(p << 1 | 1, l, r, d);
	t[p].sum = t[p << 1].sum + t[p << 1 | 1].sum;
}
long long ffind(int p, int l, int r)
{
	if (l <= t[p].l && t[p].r <= r)return t[p].sum;
	lyy(p);
	int mid = t[p].l + t[p].r >> 1;
	if (r <= mid)return ffind(p << 1, l, r);
	else if (l > mid)return ffind(p << 1 | 1, l, r);
	else return ffind(p << 1, l, r) + ffind(p << 1 | 1, l, r);
}
int n, m, l, r;
char ch;
long long d;
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)cin >> w[i];
	build(1, 1, n);
	while (m--)
	{
		cin >> ch >> l >> r;
		if (ch == 'C')
			cin >> d, modify(1, l, r, d);
		else cout << ffind(1, l, r) << endl;
	}
	return 0;
}

P3870 [TJOI2009] 开关 https://www.luogu.com.cn/problem/P3870

#include <iostream>
using namespace std;
const int N = 1e5 + 1;
int w[N];
struct node
{
	int l, r, sum, add;
}t[N << 2];
void build(int p, int l, int r)
{
	t[p] = { l,r };
	if (l == r) { t[p] = { l,l,0 }; return; }
	int mid = l + r >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
}
void lyy(int p)
{
	if (t[p].add & 1)
	{
		t[p << 1].sum = t[p << 1].r - t[p << 1].l + 1 - t[p << 1].sum;
		t[p << 1 | 1].sum = t[p << 1 | 1].r - t[p << 1 | 1].l + 1 - t[p << 1 | 1].sum;
		++t[p << 1].add;
		++t[p << 1 | 1].add;
		t[p].add = 0;
	}
	else t[p].add = 0;
}
void modify(int p, int l, int r)
{
	if (l <= t[p].l && t[p].r <= r)
	{
		++t[p].add;
		t[p].sum = t[p].r - t[p].l + 1 - t[p].sum;
		return;
	}
	lyy(p);
	int mid = t[p].l + t[p].r >> 1;
	if (l <= mid)modify(p << 1, l, r);
	if (r > mid)modify(p << 1 | 1, l, r);
	t[p].sum = t[p << 1].sum + t[p << 1 | 1].sum;
}
int ffind(int p, int l, int r)
{
	if (l <= t[p].l && t[p].r <= r)return t[p].sum;
	lyy(p);
	int mid = t[p].l + t[p].r >> 1;
	if (r <= mid)return ffind(p << 1, l, r);
	else if (l > mid)return ffind(p << 1 | 1, l, r);
	else
	{
		return ffind(p << 1, l, r) + ffind(p << 1 | 1, l, r);
	}
}
int n, m, c, a, b;
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	build(1, 1, n);
	while (m--)
	{
		cin >> c >> a >> b;
		if (a > b)swap(a, b);
		if (c)cout << ffind(1, a, b) << endl;
		else modify(1, a, b);
	}
	return 0;
}

算法竞赛进阶指南p241的扫描线看着好难,还是看看远方的分块算法吧。

标签:www,标记,int,C++,算法,从零开始,long,P3870,com
From: https://www.cnblogs.com/neophyte/p/18249828

相关文章