1. 程式人生 > 其它 >洛谷P3130 haybalesCounting Haybale P 題解

洛谷P3130 haybalesCounting Haybale P 題解

題目

[USACO15DEC]haybalesCounting Haybale P

題解

最近剛剛自學了線段樹這個資料結構,恰巧做到了這道線段樹的模板題。其實也沒有什麼好多說的,接觸過線段樹的大犇肯定覺得很簡單。這道題注意的是修改區間的值時用到了lazy思想,如果只是用樸素的修改法則會超時。

果然,用樸素的方法更新值果然TLE了。

於是,我使用了lazy陣列,這樣可以儘可能地減少不必要的修改(如果有不理解的小夥伴可以上網搜尋線段樹lazy的含義與用法),最終終於AK了。

程式碼

這是TLE的程式碼(請勿學習)

#include<iostream>
using namespace std;
int n, m;
typedef long long ll;
#define MAX 200001
ll sum[MAX << 2];
int mm[MAX << 2];
int a[MAX];
char c;
int le, ri, p;

inline void pushup(int rt) 
{
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
	mm[rt] = min(mm[rt << 1], mm[rt << 1 | 1]);
}

void build(int l, int r, int cur)
{
	if (l == r)
	{
		sum[cur] = a[l];
		mm[cur] = a[l];
		return;
	}
	int mid = (l + r)>>1;
	build(l, mid, cur << 1);
	build(mid + 1, r, cur << 1 | 1);
	pushup(cur);
}

ll Sum(int L, int R, int l, int r, int cur)
{
	if (l >= L && r <= R)
		return sum[cur];
	int mid = (l + r) >> 1;
	ll res = 0;
	if (mid >= L)
		res += Sum(L, R, l, mid, cur << 1);
	if (mid < R)
		res += Sum(L, R, mid + 1, r, cur << 1 | 1);
	return res;
}

ll Min(int L, int R, int l, int r, int cur)
{
	if (l>=L&&r<=R)
		return mm[cur];
	int mid = (l + r) >> 1;
	if (mid >= R)
		return Min(L, R, l, mid, cur << 1);
	else if (mid < L)
		return Min(L, R, mid + 1, r, cur << 1 | 1);
	return min(Min(L, R, l, mid, cur << 1), Min(L, R, mid + 1, r, cur << 1 | 1));
}

void update(int L, int R, int l, int r, int cur, int z)
{
	if (l == r)
	{
		sum[cur] += z;
		mm[cur] += z;
		return;
	}
	int mid = (l + r) >> 1;
	if (mid >= L)
		update(L, R, l, mid, cur << 1, z);
	if (mid < R)
		update(L, R, mid + 1, r, cur << 1 | 1, z);
	pushup(cur);
}

int main()
{
	ios::sync_with_stdio(false);
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	build(1, n, 1);
	for (int i = 0; i < m; i++)
	{
		cin >> c;
		if (c == 'M')
		{
			cin >> le >> ri;
			cout << Min(le, ri, 1, n, 1) << '\n';
		}
		else if (c == 'S')
		{
			cin >> le >> ri;
			cout<<Sum(le, ri, 1, n, 1)<<'\n';
		}
		else
		{
			cin >> le >> ri >> p;
			update(le, ri, 1, n, 1, p);
		}
	}
	return 0;
}

接下來是AC的(現學現碼)

#include<iostream>
using namespace std;
int n, m;
typedef long long ll;
#define MAX 200001
ll sum[MAX << 2];
int mm[MAX << 2];
ll lazy[MAX << 2];
int a[MAX];
char c;
int le, ri, p;

inline void pushup(int rt) 
{
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
	mm[rt] = min(mm[rt << 1], mm[rt << 1 | 1]);
}

inline void pushdown(int rt, int l, int r)
{
	lazy[rt << 1] += lazy[rt], lazy[rt << 1 | 1] += lazy[rt];
	int mid = (l + r) / 2;
	sum[rt << 1] += lazy[rt] * (mid - l + 1);
	sum[rt << 1 | 1] += lazy[rt] * (r - mid);
	mm[rt << 1] += lazy[rt];
	mm[rt << 1 | 1] += lazy[rt];
	lazy[rt] = 0;
}

void build(int l, int r, int cur)
{
	if (l == r)
	{
		sum[cur] = a[l];
		mm[cur] = a[l];
		return;
	}
	int mid = (l + r)>>1;
	build(l, mid, cur << 1);
	build(mid + 1, r, cur << 1 | 1);
	pushup(cur);
}

ll Sum(int L, int R, int l, int r, int cur)
{
	if (l >= L && r <= R)
		return sum[cur];
	if (lazy[cur])
		pushdown(cur, l, r);
	int mid = (l + r) >> 1;
	ll res = 0;
	if (mid >= L)
		res += Sum(L, R, l, mid, cur << 1);
	if (mid < R)
		res += Sum(L, R, mid + 1, r, cur << 1 | 1);
	return res;
}

ll Min(int L, int R, int l, int r, int cur)
{
	if (l>=L&&r<=R)
		return mm[cur];
	if (lazy[cur])
		pushdown(cur, l, r);
	int mid = (l + r) >> 1;
	if (mid >= R)
		return Min(L, R, l, mid, cur << 1);
	else if (mid < L)
		return Min(L, R, mid + 1, r, cur << 1 | 1);
	return min(Min(L, R, l, mid, cur << 1), Min(L, R, mid + 1, r, cur << 1 | 1));
}

void update(int L, int R, int l, int r, int cur, int z)
{
	if (l >= L&&r <= R)
	{
		sum[cur] += (ll)z * (r - l + 1);
		mm[cur] += z;
		lazy[cur] += z;
		return;
	}
	if (lazy[cur])
		pushdown(cur, l, r);
	int mid = (l + r) >> 1;
	if (mid >= L)
		update(L, R, l, mid, cur << 1, z);
	if (mid < R)
		update(L, R, mid + 1, r, cur << 1 | 1, z);
	pushup(cur);
}

int main()
{
	ios::sync_with_stdio(false);
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	build(1, n, 1);
	for (int i = 0; i < m; i++)
	{
		cin >> c;
		if (c == 'M')
		{
			cin >> le >> ri;
			cout << Min(le, ri, 1, n, 1) << '\n';
		}
		else if (c == 'S')
		{
			cin >> le >> ri;
			cout<<Sum(le, ri, 1, n, 1)<<'\n';
		}
		else
		{
			cin >> le >> ri >> p;
			update(le, ri, 1, n, 1, p);
		}
	}
	return 0;
}

感覺自己還是太菜了。