现在的位置: 首页 > 综合 > 正文

UVALive 5694 Adding New Machine

2013年10月28日 ⁄ 综合 ⁄ 共 3425字 ⁄ 字号 评论关闭

线段树扫描线。

题意: 在一个n*m平面内,有一些不重叠的矩形(可能退化成点或线),现在让你把一根给定长度的线竖直或水平地放进平面,要求不与任何原来存在的矩形重合,问有多少种放法。

解法: 在一根长度为a的线段上放置一根长度为b的线段共有a-b+1种放法。那么将给定的矩形拆成两根线段,用扫描线横着扫一次,竖着扫一次,就可以得到答案。有区间合并的过程。范围较大需要离散化。

本人在拆矩形时因为拆的是闭区间,一个矩形8条线,再因为线段树的4倍空间需求和维护变量的4倍空间需求,总共有5W个矩形,在ZOJ上内存堪堪卡过去。

注意一下计算时的讨论,还有长度为1的情况,见代码,不赘述。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define clr(a,b) memset(a,b,sizeof(a))
typedef long long lld;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ls (rt<<1)
#define rs (rt<<1|1)

const int MAXN = 400010;
int w,h,n,len;
int san[MAXN],st;
struct point {
    int x[2],y[2];
}sp[MAXN];
struct Seg {
    int l,r,h,s;
    Seg(){}
    Seg(int l, int r, int h, int s) : 
        l(l), r(r), h(h), s(s) {}
    bool operator < (const Seg &tt) const {
        if(h == tt.h) return s > tt.s;
        return h < tt.h;
    }
}ss[MAXN<<2];
int tot;
lld ans;
int lpa[MAXN<<2],rpa[MAXN<<2],sum[MAXN<<2],cnt[MAXN<<2];

int Count(int x) {
    return x < len ? 0 : x-len+1;
}

void up(int l, int r, int rt) {
    int m = l+r>>1;
    sum[rt] = sum[ls] + sum[rs];
    lpa[rt] = lpa[ls];
    if(lpa[rt] == m-l+1) lpa[rt] += lpa[rs];
    rpa[rt] = rpa[rs];
    if(rpa[rt] == r-m) rpa[rt] += rpa[ls];

    sum[rt] -= Count(san[m]-san[m-rpa[ls]+1]+1);
    sum[rt] -= Count(san[m+lpa[rs]]-san[m+1]+1);
    sum[rt] += Count(san[m+lpa[rs]]-san[m-rpa[ls]+1]+1);
}

void build(int l, int r, int rt) {
    sum[rt] = Count(san[r]-san[l]+1);
    lpa[rt] = rpa[rt] = r-l+1;
    cnt[rt] = 0;
    if(l == r) return ;
    int m = l+r>>1;
    build(lson);
    build(rson);
}

void update(int L, int R, int x, int l, int r, int rt) {
    if(L<=l && r<=R) {
        cnt[rt] += x;
        if(cnt[rt] == 0) {
            lpa[rt] = rpa[rt] = r - l + 1;
            sum[rt] = Count(san[r]-san[l]+1);
        }
        else {
            rpa[rt] = lpa[rt] = 0;
            sum[rt] = 0;
        }
        return ;
    }
    else {
        int m = l+r>>1;
        if(L<=m) update(L,R,x,lson);
        if(m< R) update(L,R,x,rson);
        up(l,r,rt);
    }
}

void gaox() {
    if(n == 0) {
        ans += (lld)Count(w) * h;
        return ;
    }
    if(w < len) return ;
    tot = 0;
    REP(i,0,n) {
        ss[tot++] = Seg(sp[i].x[0],sp[i].x[1],sp[i].y[0],1);
        ss[tot++] = Seg(sp[i].x[0],sp[i].x[1],sp[i].y[1],-1);
    }
    sort(ss,ss+tot);
    int l = lower_bound(san,san+st,1) - san;
    int r = lower_bound(san,san+st,w) - san;
    build(l,r,1);
    REP(i,0,tot-1) {
        int L = lower_bound(san,san+st,ss[i].l) - san;
        int R = lower_bound(san,san+st,ss[i].r) - san;
        if(ss[i].s < 0 && (ss[i-1].h != ss[i].h || ss[i-1].s != ss[i].s))
            ans += sum[1];
        update(L,R,ss[i].s,l,r,1);
        if(ss[i].s < 0 && ss[i+1].h != ss[i].h) ans += (lld)sum[1] * (ss[i+1].h - ss[i].h - 1);
        else if(ss[i].s > 0) ans += (lld)sum[1] * (ss[i+1].h - ss[i].h);
    }

    if(ss[tot-1].s != ss[tot-2].s || ss[tot-1].h != ss[tot-2].h) ans += sum[1];
    ans += (lld)Count(w) * (ss[0].h-1 + h-ss[tot-1].h);
}

void gaoy() {
    if(n == 0) {
        ans += (lld)Count(h) * w;
        return ;
    }
    if(h < len) return ;
    tot = 0;
    REP(i,0,n) {
        ss[tot++] = Seg(sp[i].y[0],sp[i].y[1],sp[i].x[0],1);
        ss[tot++] = Seg(sp[i].y[0],sp[i].y[1],sp[i].x[1],-1);
    }
    sort(ss,ss+tot);
    int l = lower_bound(san,san+st,1) - san;
    int r = lower_bound(san,san+st,h) - san;
    build(l,r,1);
    REP(i,0,tot-1) {
        int L = lower_bound(san,san+st,ss[i].l) - san;
        int R = lower_bound(san,san+st,ss[i].r) - san;
        int temp;
        if(ss[i].s < 0 && (ss[i-1].h != ss[i].h || ss[i-1].s != ss[i].s)) ans += sum[1];
        update(L,R,ss[i].s,l,r,1);
        if(ss[i].s < 0 && ss[i+1].h != ss[i].h) ans += (lld)sum[1] * (ss[i+1].h - ss[i].h - 1);
        else if(ss[i].s > 0) ans += (lld)sum[1] * (ss[i+1].h - ss[i].h);
    }
    if(ss[tot-1].s != ss[tot-2].s || ss[tot-1].h != ss[tot-2].h) ans += sum[1];
    ans += (lld)Count(h) * (ss[0].h-1 + w-ss[tot-1].h);
}

int main() {
    while(~scanf("%d%d%d%d", &w, &h, &n, &len)) {
        st = 0;
        ans = 0;
        san[st++] = 1;
        san[st++] = w;
        san[st++] = h;
        REP(i,0,n) {
            REP(j,0,2) {
                scanf("%d%d", &sp[i].x[j],&sp[i].y[j]);
                san[st++] = sp[i].x[j];
                san[st++] = sp[i].y[j];
            }
            san[st++] = sp[i].x[0]-1;
            san[st++] = sp[i].x[1]+1;
            san[st++] = sp[i].y[0]-1;
            san[st++] = sp[i].y[1]+1;
        }
        sort(san,san+st);
        st = unique(san,san+st) - san;
        gaox();
        if(len != 1) gaoy();
        printf("%lld\n", ans);
    }
    return 0;
}

/*

4 4 3 2
3 2 3 2
2 3 2 3
3 3 4 4

ans = 10

*/

抱歉!评论已关闭.