D. Slalom

time limit per test:2 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

Little girl Masha likes winter sports, today she's planning to take part in slalom skiing.

The track is represented as a grid composed of n × m squares. There are rectangular obstacles at the track, composed of grid squares. Masha must get from the square (1, 1) to the square (n, m). She can move from a square to adjacent square: either to the right, or upwards. If the square is occupied by an obstacle, it is not allowed to move to that square.

One can see that each obstacle can actually be passed in two ways: either it is to the right of Masha's path, or to the left. Masha likes to try all ways to do things, so she would like to know how many ways are there to pass the track. Two ways are considered different if there is an obstacle such that it is to the right of the path in one way, and to the left of the path in the other way.

Help Masha to find the number of ways to pass the track. The number of ways can be quite big, so Masha would like to know it modulo109 + 7.

The pictures below show different ways to pass the track in sample tests.

Input

The first line of input data contains three positive integers: nm and k (3 ≤ n, m ≤ 106, 0 ≤ k ≤ 105) — the size of the track and the number of obstacles.

The following k lines contain four positive integers each: x1, y1, x2, y2 (1 ≤ x1 ≤ x2 ≤ n, 1 ≤ y1 ≤ y2 ≤ m) — coordinates of bottom left, and top right squares of the obstacle.

It is guaranteed that there are no obstacles at squares (1, 1) and (n, m), and no obstacles overlap (but some of them may touch).

Output

Output one integer — the number of ways to pass the track modulo 109 + 7.

Examples

input
3 3 0
output
1
input
4 5 1
2 2 3 4
output
2
input
5 5 3
2 2 2 3
4 2 5 2
4 4 4 4
output
3

Solution

和BZOJ4422是一个类型的题。线段树扫描线+差分 优化DP    (传送门)

这个题也是一样的,转移比较好想就不说了.

把每个障碍分左边右边记录下来,然后一维线段树一维扫描线。

线段树支持区间覆盖,单点修改,区间查询和即可。

写扫描线都用结构体,记录一下x,y1,y2,0/1。这样排序会比较麻烦...有个不错的姿势,就是对每个x建一个vector,vector里面存一个pair,这样会非常方便。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
#define LL long long
inline int read()
{
int x=; char ch=getchar();
while (ch<'' || ch>'') {ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x;
}
#define MOD 1000000007
#define MAXN 1000010
int N,M,K,tp;
namespace SegmentTree
{
struct SegmentTreeNode{int l,r,size,cov,sum;}tree[MAXN<<];
#define ls now<<1
#define rs now<<1|1
inline void Update(int now) {tree[now].sum=tree[ls].sum+tree[rs].sum; tree[now].sum%=MOD;}
inline void BuildTree(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r; tree[now].size=r-l+; tree[now].cov=-;
if (l==r) return;
int mid=(l+r)>>;
BuildTree(ls,l,mid); BuildTree(rs,mid+,r);
Update(now);
}
inline void cover(int now,int D) {tree[now].cov=D; tree[now].sum=(LL)tree[now].size*D%MOD;}
inline void PushDown(int now)
{
if (tree[now].l==tree[now].r) return;
if (tree[now].cov!=-) cover(ls,tree[now].cov),cover(rs,tree[now].cov),tree[now].cov=-;
}
inline void Cover(int now,int L,int R,int D)
{
if (R<L) return;
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) {cover(now,D); return;}
int mid=(l+r)>>;
if (L<=mid) Cover(ls,L,R,D);
if (R>mid) Cover(rs,L,R,D);
Update(now);
}
inline void Modify(int now,int pos,int D)
{
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (l==r) {cover(now,D); return;}
int mid=(l+r)>>;
if (pos<=mid) Modify(ls,pos,D);
else Modify(rs,pos,D);
Update(now);
}
inline int Query(int now,int L,int R)
{
if (R<L) return ;
int l=tree[now].l,r=tree[now].r;
PushDown(now);
if (L<=l && R>=r) return tree[now].sum;
int mid=(l+r)>>,re=;
if (L<=mid) (re+=Query(ls,L,R))%=MOD;
if (R>mid) (re+=Query(rs,L,R))%=MOD;
return re;
}
}
struct LineNode{int x,y1,y2,f;}Line[MAXN<<];
bool cmp(LineNode A,LineNode B) {return A.x==B.x? A.y1==B.y1? A.y2>B.y2 : A.y1>B.y1 : A.x<B.x;}
#define Pa pair<int,int>
set<Pa>mp;
set<Pa>::iterator is;
Pa loc;
int main()
{
N=read(),M=read(),K=read();
for (int x1,x2,y1,y2,i=; i<=K; i++)
x1=read(),y1=read(),x2=read(),y2=read(),
Line[++tp].x=x1,Line[tp].y1=y1,Line[tp].y2=y2,Line[tp].f=,
Line[++tp].x=x2+,Line[tp].y1=y1,Line[tp].y2=y2,Line[tp].f=;
SegmentTree::BuildTree(,,M);
SegmentTree::Modify(,,);
sort(Line+,Line+tp+,cmp);
int X=;
for (int i=; Line[i].x==; X++,i++) if (Line[i].f) mp.insert(make_pair(Line[i].y1,Line[i].y2));
mp.insert(make_pair(,));
for (int i=; i<=N; i++)
{
for (int j=X,tmp; Line[j].x==i; j++)
if (Line[j].f)
if (Line[j].y2<M)
loc=(*--mp.lower_bound(make_pair(Line[j].y2+,))),
tmp=SegmentTree::Query(,loc.second+,Line[j].y2+),
SegmentTree::Modify(,Line[j].y2+,tmp);
for (int j=X; Line[j].x==i; j++) if (!Line[j].f) mp.erase(make_pair(Line[j].y1,Line[j].y2));
for (int j=X; Line[j].x==i; X++,j++)
if (Line[j].f) mp.insert(make_pair(Line[j].y1,Line[j].y2)),SegmentTree::Cover(,Line[j].y1,Line[j].y2,);
}
loc=*(--mp.end());
printf("%d\n",SegmentTree::Query(,loc.first+,M)%MOD);
return ;
}

【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)的更多相关文章

  1. LOJ #2537. 「PKUWC 2018」Minimax (线段树合并 优化dp)

    题意 小 \(C\) 有一棵 \(n\) 个结点的有根树,根是 \(1\) 号结点,且每个结点最多有两个子结点. 定义结点 \(x\) 的权值为: 1.若 \(x\) 没有子结点,那么它的权值会在输入 ...

  2. UOJ#7. 【NOI2014】购票 | 线段树 凸包优化DP

    题目链接 UOJ #7 题解 首先这一定是DP!可以写出: \[f[i] = \min_{ancestor\ j} \{f[j] + (d[j] - d[i]) * p[i] + q[i]\}\] 其 ...

  3. 【学习笔记】线段树—扫描线补充 (IC_QQQ)

    [学习笔记]线段树-扫描线补充 (IC_QQQ) (感谢 \(IC\)_\(QQQ\) 大佬授以本内容的著作权.此人超然于世外,仅有 \(Luogu\) 账号 尚可膜拜) [学习笔记]线段树详解(全) ...

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

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

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

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

  6. HDU 4419 Colourful Rectangle --离散化+线段树扫描线

    题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...

  7. BZOJ-3228 棋盘控制 线段树+扫描线+鬼畜毒瘤

    3228: [Sdoi2008]棋盘控制 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 23 Solved: 9 [Submit][Status][D ...

  8. BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞

    看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...

  9. hdu 5091(线段树+扫描线)

    上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...

随机推荐

  1. 【原】设置iOS项目BuildVersion自动增加

    一.概念阐述:Build与Version的区别 在iOS中有两种“版本号”,也就是所谓的version号与build号,如下图所示: 我们用最简洁的语言来区分这两个版本号的区别以及用途如下: Vers ...

  2. IOS 序列化与反序列化NSKeyedUnarchiver

    开篇 1到底这个序列化有何作用? 面向对象的程序在运行的时候会创建一个复杂的对象图,经常要以二进制的方法序列化这个对象图,这个过程叫做Archiving. 二进制流可以通过网络或写入文件中. 当你写的 ...

  3. 基于Ruby的Watir-WebDriver自动化测试框架

    基于Ruby的watir-webdriver自动化测试方案与实施(五)   基于Ruby的watir-webdriver自动化测试方案与实施(四)   基于Ruby的watir-webdriver自动 ...

  4. Linux(Centos)系统上搭建SVN以及常见错误解答

    本文主要介绍怎样在Centos上搭建SVN,文章内容比较基础,适合小白用户学习. 1.Linux版本Centos 6.5 查看linux版本命令: cat /etc/issue 2.查看本机上是否已经 ...

  5. ORACLE外部表总结

    外部表介绍 ORACLE外部表用来存取数据库以外的文本文件(Text File)或ORACLE专属格式文件.因此,建立外部表时不会产生段.区.数据块等存储结构,只有与表相关的定义放在数据字典中.外部表 ...

  6. Python基础1

    本节内容2016-05-30 Python介绍 发展史 Python 2 0r 3? 安装 Hello word程序 变量 用户输入 模块初识 .pyc? 数据类型初识 数据运算 if...else语 ...

  7. 理解 Node.js 里的 process.nextTick()

    有很多人对Node.js里process.nextTick()的用法感到不理解,下面我们就来看一下process.nextTick()到底是什么,该如何使用. Node.js是单线程的,除了系统IO之 ...

  8. C# XML技术总结之XDocument 和XmlDocument

    引言 虽然现在Json在我们的数据交换中越来越成熟,但XML格式的数据还有很重要的地位. C#中对XML的处理也不断优化,那么我们如何选择XML的这几款处理类 XmlReader,XDocument ...

  9. 帆软报表FineReport中数据连接之Jboss配置JNDI连接

    使用sqlsever 2000数据库数据源来做实例讲解,帆软报表FineReport数据连接中Jboss配置JNDI大概的过程和WEBSPHERE以及WEBLOGIC基本相同,用JDBC连接数据库制作 ...

  10. winform修改、打开窗体、构造函数传值

    制作登录窗体: 制作一个登陆窗体,实现点击按钮关闭此窗体并打开另一个窗体 直接在按钮点击事件中,实例化一个想要打开的窗体 使用show方法打开,并把登陆窗体的visible属性改为false Form ...