现有一个宽 w ,高 h 的垂直空间,空间中有 n 个屏障,现在可以从 h+1 的高度垂直扔小球下去,如果小球遇到屏障且高度差不超过一个界限,小球就会分裂成两个继续下落,否则小球会穿过屏障。现在从每个单位宽度扔一个小球,求最终落到屏障上有多少小球。
容易想到一个 dpi,j 表示从 (i,j) 扔球得到的答案。考虑到 n 只有 105 ,中间有大量空间是没有屏障的,我们重新考虑一个从下往上的 dp 。我们从一个点 (x,y) 扔球,其实我们只关心 y 之下, x 最高的且不会被穿过的屏障是哪个。并且从每个屏障出发的答案是确定的,用 dpi 表示屏障 i 的答案, dpi = dpj+dpk , j,k 为 li−1,ri+1 下去的屏障。那么我们开一个 1−w 的线段树,维护每个坐标有用的屏障信息。从下到上地,在 hi 加入屏障 i ,在 hi+si 删除屏障 i ,这里可以方便地在线段树上使用set来维护。由此,我们得到一个 O((n+w)log2w) 的做法。
我们可以把从同一个位置扔出的小球看作一个集合,那么一个屏障最多会产生两个集合,且会至少减少一个集合,那么最多会有 w+n 个集合。我们对每个列坐标维护一个顺序栈,记录该列还存在的集合。从上往下的依次处理屏障,对于每个屏障,我们需要知道哪些集合会落在屏障上。我们建立一个线段树来维护区间中最低的集合,判断会落在屏障上后,将球的个数记录并退栈,否则该屏障处理结束。最后的答案就是栈中所有球的个数和。这样,我们得到了 O((n+w)logw) 的做法。
#include
using namespace std;
const int maxn = 2e5 + 10;
const int jyb = 1e9 + 7;
struct node
{
int l,r;
set<int>s;
}t[maxn];
int tot;
struct Barriers
{
int h,l,r,s;
bool operator < (const Barriers &b) const
{
if(s == b.s)
return h > b.h;
return s < b.s;
}
}b[maxn];
map<int,int>haha;
int ans[maxn];
int h,n,w;
int hh,l,r,s;
void build(int p,int l,int r)
{
if(l == r)
return;
int mid = (l + r) >> 1;
t[p].l = ++tot;
t[p].r = ++tot;
build(t[p].l,l,mid);
build(t[p].r,mid+1,r);
}
void change(int p,int l,int r,int L,int R,int h,int d)
{
if(L == l && R == r)
{
if(d == 1)
t[p].s.insert(h);
else
t[p].s.erase(h);
return;
}
int mid = (l + r) >> 1;
if(R <= mid)
change(t[p].l,l,mid,L,R,h,d);
else if(L > mid)
change(t[p].r,mid+1,r,L,R,h,d);
else
{
change(t[p].l,l,mid,L,mid,h,d);
change(t[p].r,mid+1,r,mid+1,R,h,d);
}
}
int query(int p,int l,int r,int pos)
{
int res = 0;
if(t[p].s.size() > 0)
res = *t[p].s.rbegin();
if(l == r)
return res;
int mid = (l + r) >> 1;
if(pos <= mid)
res = max(res,query(t[p].l,l,mid,pos));
else
res = max(res,query(t[p].r,mid+1,r,pos));
return res;
}
int main()
{
cin >> h >> w >> n;
for(int i = 1; i <= n; i++)
{
scanf("%d%d%d%d",&hh,&l,&r,&s);
b[i*2-1].h = hh;
b[i*2-1].l = l;
b[i*2-1].r = r;
b[i*2-1].s = s + hh;
b[i*2].h = hh;
b[i*2].l = l;
b[i*2].r = r;
b[i*2].s = hh;
haha[hh] = i;
}
n <<= 1;
sort(b+1,b+1+n);
build(0,1,w);
ans[0] = 1;
for(int i = 1; i <= n; i++)
{
if(b[i].h != b[i].s)
{
if(b[i].s > h)
break;
change(0,1,w,b[i].l,b[i].r,b[i].h,-1);
}
else
{
int hl,hr;
if(b[i].l == 1)
{
hr = query(0,1,w,b[i].r+1);
ans[haha[b[i].h]] = 2 * ans[haha[hr]] % jyb;
}
else if(b[i].r == w)
{
hl = query(0,1,w,b[i].l-1);
ans[haha[b[i].h]] = 2 * ans[haha[hl]] % jyb;
}
else
{
hl = query(0,1,w,b[i].l-1);
hr = query(0,1,w,b[i].r+1);
ans[haha[b[i].h]] = (ans[haha[hl]] + ans[haha[hr]]) % jyb;
}
change(0,1,w,b[i].l,b[i].r,b[i].h,1);
}
}
int sum = 0;
for(int i = 1; i <= w; i++)
{
int h = query(0,1,w,i);
sum = (sum + ans[haha[h]]) % jyb;
}
printf("%d\n",sum);
return 0;
}
#include
using namespace std;
const int maxn = 1e5 + 10;
const int jyb = 1e9 + 7;
struct group
{
int h,x;
group(int _h,int _x)
{
h = _h;
x = _x;
}
};
stack s[maxn];
struct node
{
int l,r,x;
}t[maxn << 1];
int tot;
struct Barriers
{
int h,l,r,s;
bool operator < (const Barriers &b) const
{
return h > b.h;
}
}b[maxn];
int h,n,w;
void build(int p,int l,int r)
{
if(l == r)
{
t[p].x = l;
return;
}
int mid = (l + r) >> 1;
t[p].l = ++tot;
t[p].r = ++tot;
build(t[p].l,l,mid);
build(t[p].r,mid+1,r);
t[p].x = t[t[p].l].x;
}
void del(int p,int l,int r,int pos)
{
int mid = (l + r) >> 1;
if(l == r)
{
s[pos].pop();
return;
}
int ls = t[p].l;
int rs = t[p].r;
if(pos <= mid)
del(ls,l,mid,pos);
else
del(rs,mid+1,r,pos);
int ll = t[ls].x;
int rr = t[rs].x;
if(s[rr].empty())
t[p].x = ll;
else if(s[ll].empty())
t[p].x = rr;
else
t[p].x = s[ll].top().h <= s[rr].top().h ? ll : rr;
}
void add(int p,int l,int r,int pos,const group g)
{
int mid = (l + r) >> 1;
if(l == r)
{
s[pos].push(g);
return;
}
int ls = t[p].l;
int rs = t[p].r;
if(pos <= mid)
add(ls,l,mid,pos,g);
else
add(rs,mid+1,r,pos,g);
int ll = t[ls].x;
int rr = t[rs].x;
if(s[rr].empty())
t[p].x = ll;
else if(s[ll].empty())
t[p].x = rr;
else
t[p].x = s[ll].top().h <= s[rr].top().h ? ll : rr;
}
int query(int p,int l,int r,int L,int R)
{
int mid = (l + r) >> 1;
if(l == L && r == R)
return t[p].x;
int ls = t[p].l;
int rs = t[p].r;
if(R <= mid)
return query(ls,l,mid,L,R);
else if(L > mid)
return query(rs,mid+1,r,L,R);
else
{
int ll = query(ls,l,mid,L,mid);
int rr = query(rs,mid+1,r,mid+1,R);
if(s[rr].empty())
return ll;
else if(s[ll].empty())
return rr;
else
return s[ll].top().h <= s[rr].top().h ? ll : rr;
}
}
int main()
{
cin >> h >> w >> n;
for(int i = 1; i <= n; i++)
scanf("%d%d%d%d",&b[i].h,&b[i].l,&b[i].r,&b[i].s);
sort(b+1,b+1+n);
build(0,1,w);
for(int i = 1; i <= w; i++)
s[i].push(group(h+1,1));
for(int i = 1; i <= n; i++)
{
group p(b[i].h,0);
while(1)
{
int j = query(0,1,w,b[i].l,b[i].r);
if(s[j].empty())
break;
group tmp = s[j].top();
if(tmp.h > b[i].h + b[i].s)
break;
del(0,1,w,j);
p.x = (p.x + tmp.x) % jyb;;
}
if(b[i].l == 1)
{
p.x = (p.x + p.x) % jyb;
add(0,1,w,b[i].r+1,p);
}
else if(b[i].r == w)
{
p.x = (p.x + p.x) % jyb;
add(0,1,w,b[i].l-1,p);
}
else
{
add(0,1,w,b[i].l-1,p);
add(0,1,w,b[i].r+1,p);
}
}
int sum = 0;
for(int i = 1; i <= w; i++)
while(!s[i].empty())
{
sum = (sum + s[i].top().x) % jyb;
s[i].pop();
}
printf("%d\n",sum);
return 0;
}