题意:

有一个\(h \times w\)的矩形,其中有\(n\)个水平的障碍。从上往下扔一个小球,遇到障碍后会分裂成两个,分别从障碍的两边继续往下落。

如果从太高的地方落下来,障碍会消失。

问从每一列的上方扔一个小球,最终落到下面有多少个球。

分析:

每一个障碍对应一个矩形,也就是它的有效范围,在这个范围内下落的球才会落到上面,否则障碍会消失。

维护一条从下往上的扫描线,用线段树维护\([1,w]\)区间内被障碍覆盖的集合。

在扫描的过程中计算出对每个障碍一个球落在上面最终会形成多少个球,这可以通过在线段树中查询所在区间中最高的障碍来递推。

扫描结束后,也可以用同样的方法求出每个位置落下最终形成的球数。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std; const int maxn = 100000 + 10;
const int maxnode = maxn << 2;
const int MOD = 1000000007; int h, w, n; struct Barrier
{
int l, r, h, s; void read() { scanf("%d%d%d%d", &h, &l, &r, &s); }
}; struct Event
{
int height, type, id; bool operator < (const Event& t) const {
return height < t.height || (height == t.height && type < t.type);
}
}; struct Node
{
int h, id;
bool operator < (const Node t) const {
return h > t.h;
}
}; Barrier barriers[maxn];
Event events[maxn << 1];
set<Node> S[maxnode];
int cnt[maxn], ans[maxn]; void add(int& a, int b) { a += b; if(a >= MOD) a -= MOD; } int op, id, height; void opt(int o, int L, int R, int qL, int qR) {
if(qL <= L && R <= qR) {
if(op == 0) S[o].erase((Node){ height, id });
else S[o].insert((Node){ height, id });
return;
}
int M = (L + R) / 2;
if(qL <= M) opt(o<<1, L, M, qL, qR);
if(qR > M) opt(o<<1|1, M+1, R, qL, qR);
} Node qans;
void query(int o, int L, int R, int p) {
if(!S[o].empty()) { Node tmp = *S[o].begin(); if(tmp < qans) qans = tmp; }
if(L == R) return;
int M = (L + R) / 2;
if(p <= M) query(o<<1, L, M, p);
else query(o<<1|1, M+1, R, p);
} int query(int p)
{
qans = (Node){ -1, -1 };
query(1, 1, w, p);
if(qans.id == -1) return 1;
else return ans[qans.id];
} int main()
{
int tot = 0;
scanf("%d%d%d", &h, &w, &n);
for(int i = 0; i < n; i++) {
Barrier& b = barriers[i];
b.read();
events[tot++] = (Event){ b.h, 1, i };
if(b.h + b.s <= h) events[tot++] = (Event){ b.h + b.s + 1, -1, i };
}
sort(events, events + tot);
for(int i = 0; i < tot; i++) {
id = events[i].id;
Barrier& b = barriers[id];
if(events[i].type == -1) {
op = 0; height = b.h;
opt(1, 1, w, b.l, b.r);
} else {
if(b.l == 1) ans[id] = query(b.r + 1) * 2 % MOD;
else if(b.r == w) ans[id] = query(b.l - 1) * 2 % MOD;
else ans[id] = (query(b.l - 1) + query(b.r + 1)) % MOD;
op = 1; height = b.h;
opt(1, 1, w, b.l, b.r);
}
} int res = 0;
for(int i = 1; i <= w; i++) add(res, query(i));
printf("%d\n", res); return 0;
}

CodeForces 781E Andryusha and Nervous Barriers 线段树 扫描线的更多相关文章

  1. Codeforces 781E Andryusha and Nervous Barriers 线段树 单调栈

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF781E.html 题目传送门 - CF781E 题意 有一个矩形,宽为 w ,高为 h .一开始会有 w 个 ...

  2. codeforces#1108E2. Array and Segments (线段树+扫描线)

    题目链接: http://codeforces.com/contest/1108/problem/E2 题意: 给出$n$个数和$m$个操作 每个操作是下标为$l$到$r$的数减一 选出某些操作,使$ ...

  3. Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)

    题目链接:http://codeforces.com/contest/522/problem/D 题目大意:  给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...

  4. [Codeforces 266E]More Queries to Array...(线段树+二项式定理)

    [Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...

  5. [Codeforces 280D]k-Maximum Subsequence Sum(线段树)

    [Codeforces 280D]k-Maximum Subsequence Sum(线段树) 题面 给出一个序列,序列里面的数有正有负,有两种操作 1.单点修改 2.区间查询,在区间中选出至多k个不 ...

  6. codeforces 1217E E. Sum Queries? (线段树

    codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...

  7. 51nod 1494 选举拉票 (线段树+扫描线)

    1494 选举拉票  题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题  收藏  关注 现在你要竞选一个县的县长.你去对每一个选民进 ...

  8. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  9. 【POJ-2482】Stars in your window 线段树 + 扫描线

    Stars in Your Window Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11706   Accepted:  ...

随机推荐

  1. 如何配置阿里Maven镜像

    1.下载maven的zip解压,官方下载地址为:http://maven.apache.org/download.cgi 选择需要下载maven的版本就好了 2.到下载的maven路径下,conf/s ...

  2. Linux查找文件内容(grep)

    转载链接:http://www.eguidedog.net/linux-tutorial/05-grep.php grep是Linux命令行下常用于查找过滤文本文件内容的命令.最简单的用法是: gre ...

  3. Oracle 11g服务详细介绍

    按照windows 7 64位 安装oracle 11g R2中的方法成功安装Oracle 11g后,共有7个服务,这七个服务的含义分别为: 1. Oracle ORCL VSS Writer Ser ...

  4. php 01

    PHP 一.了解php 1.什么是php PHP 超文本预处理器 服务器端的脚本语言  是一种被广泛应用的开放源代码的多用途脚本语言  他可以嵌入到html中 尤其适用web开发 2.php在web中 ...

  5. newsyslog.conf详解

    newsyslog.conf 指出了哪个日志文件要被管理,要保留多少和它们什么时候被创建.日志文件可以在它们达到一定大小或者在特定的日期被重新整理.# configuration file for n ...

  6. pysnmp使用

    install yum install python-pysnmp yum install python-pyasn1 or pip install pysnmp pip install pyasn1 ...

  7. 关于前端的交互 ajax

    对于交互来说,可以利用原生的javascript和jquery 这篇说的就是jquery 1 不是跨域的 利用$ajax({})这个函数实现的 $.ajax({ url: "", ...

  8. Codeforces 802I Fake News (hard)

    Codeforces 802I 题意:统计所有不同子串出现次数的平方的和. 想法:建一个SAM,$Ans=\sum (step[i]-step[fa[i]])*right[i]^2$ #include ...

  9. win10蓝牙添加设备无法连接

    解决方法: 打开运行窗口,输入services.msc. 找到蓝牙支持服务(或者Bluetooth Support Service),右键,属性,启动类型选择手动,启动服务. 还不行的话,此电脑右键, ...

  10. ffmpeg 命令2

    ffmpeg常用基本命令(转) [FFmpeg]FFmpeg常用基本命令 1.分离视频音频流 ffmpeg -i input_file -vcodec copy -an output_file_vid ...