【洛谷】【线段树】P1047 校门外的树

时间:2023-03-09 15:58:15
【洛谷】【线段树】P1047 校门外的树

【题目描述:】

某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。

由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。

【输入格式:】

输入文件tree.in的第一行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。

【输出格式:】

输出文件tree.out包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。

输入样例#: 

输出样例#:

输入输出样例

【算法分析:】

使用线段树来维护数轴上的点的状态,作为线段树例题虽然水也有些需要注意的地方

左端点从0开始,建树时叶子节点直接赋成1,

lazy-tag开成bool型表示这个区间被清零.

修改(及标记下传)时不必管要加几或减几,直接把区间清零

由于最后是输出[0, n]的树的数量,直接输出线段树的第一个节点就好,不需要支持查询

【代码:】

 //校门外的树
#include<iostream>
#include<cstdio>
using namespace std; const int MAXN = + ; int n, m;
struct Segment {
int sum;
bool lazy;
}t[MAXN << ]; inline int read() {
int x = , f = ; char ch = getchar();
while(ch < '' || ch > '') {
if(ch == '-') f = -;
ch = getchar();
}
while(ch >= '' && ch <= '')
x = (x << ) + (x << ) + ch - , ch = getchar();
return x * f;
} void Build(int o, int l, int r) {
if(l == r) t[o].sum = ;
else {
int mid = (l + r) >> ;
Build(o << , l, mid);
Build(o << |, mid + , r);
t[o].sum = t[o << ].sum + t[o << |].sum;
}
}
inline void down(int o, int len) {
if(!t[o].lazy) return;
t[o << ].sum = ;
t[o << |].sum = ;
t[o << ].lazy = ;
t[o << |].lazy = ;
t[o].lazy = ;
}
void Update(int o, int l, int r, int ul, int ur) {
if(ul <= l && r <= ur) {
t[o].sum = ;
t[o].lazy = ;
}
else {
down(o, r - l + );
int mid = (l + r) >> ;
if(ul <= mid) Update(o << , l, mid, ul, ur);
if(ur > mid) Update(o << |, mid + , r, ul, ur);
t[o].sum = t[o << ].sum + t[o << |].sum;
}
} int main() {
n = read(), m = read();
Build(, , n);
for(int i = ; i <= m; ++i) {
int l = read(), r = read();
Update(, , n, l, r);
}
printf("%d\n", t[].sum);
}