洛谷 P1047 校门外的树(线段树版)

本文深入探讨了线段树在实际问题中的应用,特别是在处理区间更新和查询时的技巧。文章通过一个具体题目,详细解释了如何构建和维护线段树,以及在遇到特殊边界条件时的解决方案,提供了两种有效策略。

https://www.luogu.org/problemnew/show/P1047

第一次脱离模板写线段树题目(洛谷的线段树模板题太变态了)。言归正传,这是一个未完成版的线段树,因为一直到最后都没有发现为什么第一组数据会WA.后来苦心研究之后,发现线段树处理0的时候会有问题,于是想了两个解决办法应对该情况。

这个题目唯一的坑点在于从0开始,意思是输入的500实质上有501棵树,而线段树的结点和范围都必须从1开始,这也是做这题的教训吧。

解决办法1:将数组范围,修改左边界与修改右边界各加一,也就是输入范围为500时实质上建树时是501,修改范围输入100~200实际上查询101~201.

贴上代码:

#include<algorithm>
#include <iostream>
#include  <sstream>
#include  <cstring>
#include  <cstdlib>
#include   <string>
#include   <vector>
#include   <cstdio>
#include   <math.h>
#include    <queue>
#include    <stack>
#include      <set>
typedef long long ll;
#define rep(i,a,n) for (int i = a; i < n; ++i)
#define per(i,a,n) for (int i = n-1; i >= a; --i)
#define SZ(x) ((int)x.size())
using namespace std;
//head

#define maxn 1000006
ll sx[maxn << 2];
inline ll ls(ll x) { return x << 1; }
inline ll rs(ll x) { return x << 1 | 1; }
inline void push_down(ll o, ll lc, ll rc);
inline void maintain(ll o)
{
	sx[o] = sx[ls(o)] + sx[rs(o)];
}
void build(ll o, ll lc, ll rc)
{
	if (lc == rc)
	{
		sx[o] = 1;
		return;
	}
	ll m = (lc + rc) >> 1;
	build(ls(o), lc, m);
	build(rs(o), m + 1, rc);
	maintain(o);
}
void update(ll o, ll lc, ll rc, ll ql, ll qr)
{
	if (ql <= lc && qr >= rc)
	{
		sx[o] = 0;
		push_down(o, lc, rc);
		return;
	}
	ll m = (lc + rc) >> 1;
	if (ql <= m) update(ls(o), lc, m, ql, qr);
	if (qr > m) update(rs(o), m + 1, rc, ql, qr);
	maintain(o);
}
inline void push_down(ll o, ll lc, ll rc)
{
	if (lc == rc)
	{
		sx[o] = 0;
		return;
	}
	ll m = (lc + rc) >> 1;
	push_down(ls(o), lc, m);
	push_down(rs(o), m + 1, rc);
	maintain(o);
}
int main()
{
	ll L, M;
	scanf("%lld %lld", &L, &M);
	L++;
	build(1, 1, L);
	while (M--)
	{
		ll a, b;
		scanf("%lld %lld", &a, &b);
		a++;
		b++;
		update(1, 1, L, a, b);
	}
		printf("%lld\n", sx[1]);
	return 0;
}

解决办法2:

这个是朋友想出来的,用一个flag,如果碰到0则flag = 1,如果flag = 1则答案加1

这里还有个坑就是修改0~0时线段树会炸

贴上代码:

#include<algorithm>
#include <iostream>
#include  <sstream>
#include  <cstring>
#include  <cstdlib>
#include   <string>
#include   <vector>
#include   <cstdio>
#include   <math.h>
#include    <queue>
#include    <stack>
#include      <set>
typedef long long ll;
#define rep(i,a,n) for (int i = a; i < n; ++i)
#define per(i,a,n) for (int i = n-1; i >= a; --i)
#define SZ(x) ((int)x.size())
using namespace std;
//head

#define maxn 1000006
ll sx[maxn << 2];
inline ll ls(ll x) { return x << 1; }
inline ll rs(ll x) { return x << 1 | 1; }
inline void push_down(ll o, ll lc, ll rc);
inline void maintain(ll o)
{
	sx[o] = sx[ls(o)] + sx[rs(o)];
}
void build(ll o, ll lc, ll rc)
{
	if (lc == rc)
	{
		sx[o] = 1;
		return;
	}
	ll m = (lc + rc) >> 1;
	build(ls(o), lc, m);
	build(rs(o), m + 1, rc);
	maintain(o);
}
void update(ll o, ll lc, ll rc, ll ql, ll qr)
{
	if (ql <= lc && qr >= rc)
	{
		sx[o] = 0;
		push_down(o, lc, rc);
		return;
	}
	ll m = (lc + rc) >> 1;
	if (ql <= m) update(ls(o), lc, m, ql, qr);
	if (qr > m) update(rs(o), m + 1, rc, ql, qr);
	maintain(o);
}
inline void push_down(ll o, ll lc, ll rc)
{
	if (lc == rc)
	{
		sx[o] = 0;
		return;
	}
	ll m = (lc + rc) >> 1;
	push_down(ls(o), lc, m);
	push_down(rs(o), m + 1, rc);
	maintain(o);
}
int main()
{
	ll L, M;
	int flag = 0;
	scanf("%lld %lld", &L, &M);
	build(1, 1, L);
	while (M--)
	{
		ll a, b;
		scanf("%lld %lld", &a, &b);
		if(a == 0 && b == 0)
		{
			flag = 1;
			continue;
		}
		else if(a == 0)
			flag = 1;
		update(1, 1, L, a, b);
	}
	if(flag)
	printf("%lld\n", sx[1]);
	else
	printf("%lld\n", sx[1] + 1);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值