Case 1.

本题其实不难,直接模拟就可以了。时间复杂度: \(O(L \times M)\)

Case 2.

考虑一个简单的增强:把原来的:

\[L \leq 10^4,M \leq 10^2
\]

改成:

\[L ,M\leq 10^6
\]

现在我们就不可以直接模拟了,显然考虑一个 \(L \log L\) 级别 的做法。

显然,本题是区间操作,和线段树密不可分。

“砍树”的操作可以视为区间 \(-1\) . 但困难的地方是,如果一个区间多次减\(1\),只需要减\(1\)次。

我们对每个区间记录一个 \(tag\) ,\(tag\) 只会是 \(-1\) 和 \(0\).

\(-1\) 则表示该区间整个被 \(-1\) ;\(0\) 则表示该区间还有没被减过的。

那么,我们区间修改的时候, 只要当前区间的标记是\(-1\)就直接停止;如果包含则标上\(-1\)然后走人;否则一直递归到最底层。

修改的时间复杂度: \(O(M \log L)\).

修改是解决了,那怎么查询结果呢? 我们并没有一个区间和之类的东西啊……

下面我们用一个变量 \(s\) 表示被 \(-1\) (也就是被砍的树)的个数。

从根开始走,只要当前区间的标记是\(-1\),就直接统计掉,停止;否则一直走到最底层。

然后最后答案就是 \(L-s+1\). (不要忘记 \(0\) )

那么你会问了,时间复杂度大概是多少呢?

其实这和查询区间和是一样的,都是将一个区间拆成若干个小区间,因此查询的时间复杂度是\(O(\log L)\).

那么,线段是完美地实现了本题,其时间复杂度为:

\(O(M \log L + \log L) = O(M \log L)\).

注:请不要忘记 \(0,L\) 才是根维护的区间。而不是 \(1,L\) .

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std; typedef long long ll;
const int N=1e6+1; #define L (i<<1)
#define R (i<<1)+1 inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;} struct tree{
int l,r,tag;
};
tree t[N<<2];
int n,m; inline void build_tree(int i,int l,int r) {
t[i].l=l; t[i].r=r; t[i].tag=0;
if(l==r) return;
int mid=(l+r)>>1;
build_tree(L,l,mid);
build_tree(R,mid+1,r);
} inline void change(int i,int l,int r) {
// printf("%d %d %d %d %d %d\n",i,t[i].l,t[i].r,l,r,t[i].tag);
if(t[i].tag==-1) return;
if(l<=t[i].l && t[i].r<=r) {t[i].tag=-1;return;}
if(t[i].l==t[i].r) return;
int mid=(t[i].l+t[i].r)>>1;
if(l<=mid) change(L,l,r);
if(r>mid) change(R,l,r);
} int s=0;
inline void query(int i,int l,int r) {
// printf("%d %d %d %d\n",i,l,r,t[i].tag);
if(t[i].tag==-1) {s+=r-l+1;return;}
if(l==r) return; int mid=(l+r)>>1;
if(l<=mid) query(L,l,mid);
if(r>mid) query(R,mid+1,r);
} int main(){
n=read(),m=read();
build_tree(1,0,n);
while(m--) {
int x=read(),y=read();
change(1,x,y);
} query(1,0,n);
printf("%d\n",n-s+1);
return 0;
}

Case3.

下面再考虑一个显然的优化。

将 \(L,M \leq 10^6\),改为:

\(L \leq 2 \times 10^9\),\(M \leq 10^6\).

这时 线段树、差分、离散化 都无法解决这个难题了。

你会发现:其实最简化的题意是:

求\(M\)个集合的并集。

那么就很显然了吧!将 \(M\) 个区间排序(按关键字),然后直接模拟即可。

时间复杂度即为:排序的时间加上线性的递推。 \(O(M \log M + M) = O(M \log M)\).

这样,本题的时间复杂度就抛开了 \(L\).

空间复杂度:\(O(M)\)

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std; const int N=1e6+1; inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;} int n,m,ans=0;
pair<int,int>a[N]; int main(){
n=read(),m=read();
for(int i=1;i<=m;i++) a[i].first=read(),a[i].second=read();
sort(a+1,a+1+m);
int nx=a[1].first,ny=a[1].second;
for(int i=2;i<=m;i++) {
if(ny<=a[i].first) ans+=(ny-nx+1),nx=a[i].first,ny=a[i].second; //两个集合没有交集,直接统计
else if(ny<=a[i].second) ny=a[i].second; //有交集则扩展当前集合
} ans+=(ny-nx)+1;
printf("%d\n",n-ans-1); //最后减去被砍的树即可。+1是因为有0这个点。
return 0;
}

洛谷 P1047 校门外的树 题解的更多相关文章

  1. 洛谷P1047校门外的树题解

    题目 此题是一个模拟题,但需要注意的一点就是它的树是从数轴的0开始,所以我们也要从0开始,这样才能实现代码. 代码: #include<iostream> using namespace ...

  2. 洛谷P1047 校门外的树

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

  3. 洛谷——P1047 校门外的树

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

  4. 洛谷 P1047 校门外的树(待完善)

    链接:https://www.luogu.org/problemnew/show/P1047 题目: 题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是11米.我们可以把马路看 ...

  5. 洛谷 P1047 校门外的树

    #include<iostream> #include<vector> #include<algorithm> using namespace std; ]; in ...

  6. 洛谷 p1047 校门外的树 线段树做法

    非常easy, 注意一下它是两端开始,也就是说0的位置也有一棵树就好了 我由于太弱了,一道红题交了4,5遍 由于树的砍了就没了,lazy标记最大就是1; 直接贴代码吧 #include<bits ...

  7. Java实现 洛谷 P1047 校门外的树

    import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = ...

  8. 洛谷——P1276 校门外的树(增强版)

    P1276 校门外的树(增强版) 题目描述 校门外马路上本来从编号0到L,每一编号的位置都有1棵树.有砍树者每次从编号A到B处连续砍掉每1棵树,就连树苗也不放过(记 0 A B ,含A和B):幸运的是 ...

  9. 洛谷 P1276 校门外的树(增强版)

    题目描述 校门外马路上本来从编号0到L,每一编号的位置都有1棵树.有砍树者每次从编号A到B处连续砍掉每1棵树,就连树苗也不放过(记 0 A B ,含A和B):幸运的是还有植树者每次从编号C到D 中凡是 ...

随机推荐

  1. 基于USB接口芯片CH372的人机接口设备设计与实现(转)

    摘 要: 基于一种新型USB 总线接口芯片CH372,设计出一种人机接口设备-USB 鼠标.阐述了CH372 的工作原理和特点,给出了系统的硬件电路图:在软件设计中,分析了HID 类设备描述符枚举过程 ...

  2. Hadoop2.7搭建

    Hadoop最底部是 Hadoop Distributed File System(HDFS),它存储Hadoop集群中所有存储节点上的文件.HDFS(对于本文)的上一层是MapReduce 引擎,该 ...

  3. Flash之后是不是该IE浏览器了

    Flash死亡,Adobe推荐大家拥抱HTML5. 其实Flash本身也是支持手机端的. 一.Flash宣告死亡 Adoebe官方网站发布了公告,2020年12月30日起终止支援Flash.目前Chr ...

  4. 自动清理IIS log 日志脚本

    系统环境:windows server 2012 r2 IIS 版本:IIS8 操作实现清理IIS log File 脚本如下: @echo off ::自动清理IIS Log file set lo ...

  5. LeetCode--链表3-经典问题

    LeetCode--链表3-经典问题 题1 反转链表 第一次代码超出时间限制 原因是,反转之后链表的尾部节点和头结点连上了 /** * Definition for singly-linked lis ...

  6. paddlepaddle目标检测之水果检测(yolov3_mobilenet_v1)

    一.创建项目 (1)进入到https://aistudio.baidu.com/aistudio/projectoverview/public (2)创建项目 点击添加数据集:找到这两个 然后创建即可 ...

  7. ASP.NET CORE 管道模型及中间件使用解读

    说到ASP.NET CORE 管道模型不得不先来看看之前的ASP.NET 的管道模型,两者差异很大,.NET CORE 3.1 后完全重新设计了框架的底层,.net core 3.1 的管道模型更加灵 ...

  8. Git 相关问题分享,git reset与git revert的区别?

    1.如果我在git add 后想要撤销操作,该怎么做? 使用 git rm --cache [文件名/ *] 或者 git reset HEAD, 为什么这个命令也会有效果呢,实际上reset将 HE ...

  9. 基础JavaScript练习(三)总结

    任务目的 实践JavaScript数组.字符串相关操作 任务描述 基于任务四进行升级 将新元素输入框从input改为textarea 允许一次批量输入多个内容,格式可以为数字.中文.英文等,可以通过用 ...

  10. 钉钉小程序不用canvas在后端绘图前端用image标签获取图片的实践

    公司的需求要用电子员工卡代替用了N久的工作证,在各种场合刷二维码来代替刷卡.在钉钉小程序里实现.感觉这回又要躺坑里了. 钉钉小程序第一次做.我这个自封的GDI+大神才不要想用钉钉jsapi的方式用ca ...