uva 1492 - Adding New Machine(线段树)

题目链接:uva 1492 - Adding New Machine

题目大意:在一个RC矩阵上有N台旧的机器,给定每个机器的占地,现在要添加一台1M的机器,问有多少种摆放方法。

解题思路:问题可以转化成矩形覆盖问题,对于每台旧的机器,假设考虑对应每个位置向右放,那么左边的M-1个位置是不能放的,以及右边界左边的M-1个位置。用线段树解决矩形覆盖,x,y坐标分别处理一次。注意M=1的情况。

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
typedef long long ll;

#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)+1)

const int maxn = 50100;

ll N;
int M;
int x[2][maxn], y[2][maxn];
vector<int> bset, vec;

struct Segment {
    int l, r, h, v;
    void set(int l, int r, int h, int v) {
        this->l = l;
        this->r = r;
        this->h = h;
        this->v = v;
    }
}seg[maxn*2], node[maxn*8];

inline bool cmp (const Segment& a, const Segment& b) {
    return a.h < b.h;
}

inline int search (int x) {
    return lower_bound(bset.begin(), bset.end(), x) - bset.begin();
}

inline void get_hashkey () {
    sort(vec.begin(), vec.end());
    bset.push_back(vec[0]);

    for (int i = 1; i < vec.size(); i++) {
        if (vec[i] != vec[i-1])
            bset.push_back(vec[i]);
    }
}

inline void add_segment (int i, int h, int l, int r, int v) {
    seg[i].set(l, r, h, v);
    vec.push_back(l);
    vec.push_back(r);
}

inline void pushup (int u) {
    if (node[u].h)
        node[u].v = bset[node[u].r+1] - bset[node[u].l];
    else if (node[u].l == node[u].r)
        node[u].v = 0;
    else
        node[u].v = node[lson(u)].v + node[rson(u)].v;
}

void build_segTree (int u, int l, int r) {
    node[u].set(l, r, 0, 0);
    if (l == r) {
        pushup(u);
        return ;
    }

    int mid = (l + r) / 2;
    build_segTree(lson(u), l, mid);
    build_segTree(rson(u), mid + 1, r);
    pushup(u);
}

ll query_segTree (int u, int l, int r) {
    if (l <= node[u].l && node[u].r <= r)
        return node[u].v;

    int mid = (node[u].l + node[u].r) / 2;
    ll ret = 0;
    if (l <= mid)
        ret += query_segTree(lson(u), l, r);
    if (r > mid)
        ret += query_segTree(rson(u), l, r);
    return ret;
}

void add_segTree (int u, int l, int r, int v) {
    if (l <= node[u].l && node[u].r <= r) {
        node[u].h += v;
        pushup(u);
        return;
    }

    int mid = (node[u].l + node[u].r) / 2;
    if (l <= mid)
        add_segTree(lson(u), l, r, v);
    if (r > mid)
        add_segTree(rson(u), l, r, v);
    pushup(u);
}

ll solve (int x[2][maxn], int y[2][maxn], ll R, ll C) {

    if (N == 0)
        return 1LL * C * (R - M + 1);

    int n = 0;
    vec.clear();
    bset.clear();

    for (int i = 0; i < N; i++) {
        add_segment(n++, x[0][i] - 1, max(y[0][i] - M, 0), y[1][i], 1);
        add_segment(n++, x[1][i], max(y[0][i] - M, 0), y[1][i], -1);
    }

    add_segment(n++, 0, max((int)R + 1 - M, 0), R, 1);
    add_segment(n++, C, max((int)R + 1 - M, 0), R, -1);

    get_hashkey();
    sort(seg, seg + n, cmp);

    int size = bset.size() - 2;
    build_segTree (1, 0, size);

    ll ret = 0;
    for (int i = 0; i < n; i++) {
        ll tmp = query_segTree(1, 0, size);
        if (i)
            ret += tmp * (seg[i].h - seg[i-1].h);
        add_segTree(1, search(seg[i].l), search(seg[i].r) - 1, seg[i].v);
    }

    return R * C - ret;
}

int main () {
    ll R, C;
    while (scanf("%lld%lld%lld%d", &R, &C, &N, &M) == 4) {
        for (int i = 0; i < N; i++)
            scanf("%d%d%d%d", &x[0][i], &y[0][i], &x[1][i], &y[1][i]);

        ll ans = solve(x, y, C, R) + solve(y, x, R, C);

        if (M == 1)
            ans /= 2;
        printf("%lld\n", ans);
    }
    return 0;
}

你可能感兴趣的:(uva 1492 - Adding New Machine(线段树))