洛谷傳送門
Atcoder傳送門
題目大意
數軸上有個點,每個點初始時在位置,以的速度向數軸正方向前進
初始時刻,你可以選擇一些點爲其染色,之後的行走過程中,染色的點會將其碰到的所有點都染上色,之後被染上色的點亦是如此
在所有種初始染色方案中,問有多少種初始染色方案,能使得最終所有的點都被染色?答案對取模
輸入輸出格式
輸入格式
第一行一個正整數。
以下行, 每行兩個正整數。
輸出格式
輸出一個正整數, 表示方案數對取模的結果。
輸入輸出樣例
輸入樣例#1:
3
2 5
6 1
3 7
輸出樣例#1:
6
輸入樣例#2:
4
3 7
2 9
8 16
10 8
輸出樣例#2:
9
解題分析
考慮點被染色, 然後導致點被染色的情況:
- 點速度比慢, 但在點前面。
- 點速度比快, 但在點後面。
- 點速度比慢, 在後面, 但存在點比點速度慢, 在前面。
- 點速度比快, 在前面, 但存在點比點速度快, 在後面。
然後我們觀察第3、 4點, 發現只需要按速度把所有點排序,找到比速度慢且在前面的第一個點, 比速度快且在後面的最後一個點, 那麼對於每個點染色都會導致的點全部染色。
然後一個數據結構維護就好了。
代碼如下:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <climits>
#include <set>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MX 200500
#define gc getchar()
#define ls (now << 1)
#define rs (now << 1 | 1)
#define ll long long
#define MOD 1000000007
#define lbt(i) ((i) & (-(i)))
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int n, bd;
int tree[MX];
struct INFO {int pos, spd;} dat[MX];
struct Seg {int lb, rb;} seg[MX];
IN bool operator < (const INFO &x, const INFO &y) {return x.spd < y.spd;}
IN bool operator < (const Seg &x, const Seg &y) {return x.rb == y.rb ? x.lb < y.lb : x.rb < y.rb;}
namespace SGT1
{
int mn[MX << 2], mx[MX << 2];
IN void pushup(R int now)
{
mn[now] = min(mn[ls], mn[rs]);
mx[now] = max(mx[ls], mx[rs]);
}
void build (R int now, R int lef, R int rig)
{
if (lef == rig) return mn[now] = mx[now] = dat[lef].pos, void();
int mid = lef + rig >> 1;
build(ls, lef, mid), build(rs, mid + 1, rig);
pushup(now);
}
int qmin(R int now, R int lef, R int rig, R int lb, R int rb)
{
if (lef >= lb && rig <= rb) return mn[now];
int mid = lef + rig >> 1, ret = INT_MAX;
if (lb <= mid) ret = qmin(ls, lef, mid, lb, rb);
if (rb > mid) ret = min(ret, qmin(rs, mid + 1, rig, lb, rb));
return ret;
}
int qmax(R int now, R int lef, R int rig, R int lb, R int rb)
{
if (lef >= lb && rig <= rb) return mx[now];
int mid = lef + rig >> 1, ret = -INT_MAX;
if (lb <= mid) ret = qmax(ls, lef, mid, lb, rb);
if (rb > mid) ret = max(ret, qmax(rs, mid + 1, rig, lb, rb));
return ret;
}
int qpos(R int now, R int lef, R int rig, R int lb, R int rb, R int tar, R bool typ)
{
if (lef == rig) return lef;
int mid = lef + rig >> 1;
if (!typ)//to query the most left point with pos > tar
{
if (mx[ls] >= tar) return qpos(ls, lef, mid, lb, rb, tar, typ);
else return qpos(rs, mid + 1, rig, lb, rb, tar, typ);
}
else
{
if (mn[rs] <= tar) return qpos(rs, mid + 1, rig, lb, rb, tar, typ);
else return qpos(ls, lef, mid, lb, rb, tar, typ);
}
}
}
IN void add(R int pos, R int v)
{for (; pos <= bd; pos += lbt(pos)) (tree[pos] += v) %= MOD;}
IN int qpfix(R int pos)
{
int ret = 0;
for (; pos; pos -= lbt(pos)) (ret += tree[pos]) %= MOD;
return ret;
}
IN int query(R int lb, R int rb) {return (qpfix(rb) - qpfix(lb - 1) + MOD) % MOD;}
int main(void)
{
in(n); bd = n + 1;
for (R int i = 1; i <= n; ++i) in(dat[i].pos), in(dat[i].spd);
std::sort(dat + 1, dat + 1 + n);
SGT1::build(1, 1, n);
for (R int i = 1; i <= n; ++i)
{
seg[i].lb = SGT1::qpos(1, 1, n, 1, i, dat[i].pos, 0);
seg[i].rb = SGT1::qpos(1, 1, n, i, n, dat[i].pos, 1);
}
std::sort(seg + 1, seg + 1 + n);
add(1, 1);
for (R int i = 1; i <= n; ++i) seg[i].lb++, seg[i].rb++, add(seg[i].rb, query(seg[i].lb - 1, seg[i].rb));
printf("%d", query(n + 1, n + 1));
}