1. 程式人生 > >Codeforces 780G Andryusha and Nervous Barriers

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,kli1,ri+1下去的屏障。那麼我們開一個1

w的線段樹,維護每個座標有用的屏障資訊。從下到上地,在hi加入屏障i,在hi+si刪除屏障i,這裡可以方便地線上段樹上使用set來維護。由此,我們得到一個O((n+w)log2w)的做法。

我們可以把從同一個位置扔出的小球看作一個集合,那麼一個屏障最多會產生兩個集合,且會至少減少一個集合,那麼最多會有w+n個集合。我們對每個列座標維護一個順序棧,記錄該列還存在的集合。從上往下的依次處理屏障,對於每個屏障,我們需要知道哪些集合會落在屏障上。我們建立一個線段樹來維護區間中最低的集合,判斷會落在屏障上後,將球的個數記錄並退棧,否則該屏障處理結束。最後的答案就是棧中所有球的個數和。這樣,我們得到了O

((n+w)logw)的做法。

#include <bits/stdc++.h>

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 <bits/stdc++.h>

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<group>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;
}