Codeforces 780G Andryusha and Nervous Barriers

现有一个宽 w ,高 h 的垂直空间,空间中有 n 个屏障,现在可以从 h+1 的高度垂直扔小球下去,如果小球遇到屏障且高度差不超过一个界限,小球就会分裂成两个继续下落,否则小球会穿过屏障。现在从每个单位宽度扔一个小球,求最终落到屏障上有多少小球。

容易想到一个 dpi,j 表示从 (i,j) 扔球得到的答案。考虑到 n 只有 105 ,中间有大量空间是没有屏障的,我们重新考虑一个从下往上的 dp 。我们从一个点 (x,y) 扔球,其实我们只关心 y 之下, x 最高的且不会被穿过的屏障是哪个。并且从每个屏障出发的答案是确定的,用 dpi 表示屏障 i 的答案, dpi = dpj+dpk , j,k li1,ri+1 下去的屏障。那么我们开一个 1w 的线段树,维护每个坐标有用的屏障信息。从下到上地,在 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;
    }
};
stacks[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;
}

你可能感兴趣的:(动态规划DP,codeforces)