hdu4052Adding New Machine(线段树求矩形面积并)

题目请戳这里

题目大意:给一个w*h的矩阵,给n个矩形,n个矩阵互不相交。再给一个1*m的矩形,要求与给定的n个矩形不相交,求能摆放的方案种数。

题目分析:w和h很大,n有50000,所以离散化+线段树。因为要摆放的矩形是1*m的,所以这个矩形只有2种姿势:横着or竖着。所以从左向右扫描一遍,求出空地的面积并,从上向下扫描一遍,求剩余面积并相加即可。不过要对之前的n个矩形处理一下:对于第i个矩形,从左向右扫描的话,将此矩形的右界向右伸长m-1,因为从左向右是恒着扫描的,如果1*m的矩形要横着放,那么矩形i的右界的右边m-1个格子显然也是不能放的,竖直方向也是同理,下界向下伸长m-1,直到越界为止。一开始的话,大矩形左到右和上到下1~m-1这个范围赋值一个很大的数,因为无论何时,这段都是不能放矩形的。大矩形的左右界,上下界也作为一条扫描线方便些。

trick:当m为1的时候,水平竖直放都一样,所以求出来的答案除2!

ps:比赛的时候以为是dp,竟然没看出是道线段树,简直弱爆了。。。

pps:用线段树写个矩形面积并写了一天,简直弱爆了。。。

ppps:zoj竟然用不了__int64,太ws了,累觉不爱了。。。

详情请见代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 500005;
int hx[N + N],hy[N + N],nx,ny;
struct node
{
    int a,b,c,d;
}linex[N],liney[N];
int w,h,n,m;
int cmp(struct node a,struct node b)
{
    return a.a < b.a;
}
struct nd
{
    int len,cover;
};
struct sgt
{
    struct nd tree[N<<2];
    void init(int num,int s,int e)
    {
        tree[num].cover = tree[num].len = 0;
        if(s == e)
            return;
        int mid = (s + e)>>1;
        init(num<<1,s,mid);
        init(num<<1|1,mid + 1,e);
    }
    void insert(int num,int s,int e,int l,int r,int val,int dir)
    {
        if(s == e)
        {
            tree[num].cover += val;
            if(tree[num].cover)
            {
                if(dir)
                    tree[num].len = hx[e + 1] - hx[s];
                else
                    tree[num].len = hy[e + 1] - hy[s];
            }
            else
                tree[num].len = 0;
            return;
        }
        if(s == l && e == r)
        {
            if(tree[num].cover > 0 || val > 0)//少了val>0会T.....
            {
                tree[num].cover += val;
                if(tree[num].cover > 0)
                {
                    if(dir)
                        tree[num].len = hx[e + 1] - hx[s];
                    else
                        tree[num].len = hy[e + 1] - hy[s];
                }
                else
                    tree[num].len = tree[num<<1].len + tree[num<<1|1].len;
                return;
            }
        }
        int mid = (s + e)>>1;
        if(tree[num].cover)
        {
            tree[num<<1].cover += tree[num].cover;
            tree[num<<1|1].cover += tree[num].cover;
            if(dir)//再往下更新一层!!!
            {
                tree[num<<1].len = hx[mid + 1] - hx[s];
                tree[num<<1|1].len = hx[e + 1] - hx[mid + 1];
            }
            else
            {
                tree[num<<1].len = hy[mid + 1] - hy[s];
                tree[num<<1|1].len = hy[e + 1] - hy[mid + 1];
            }
            tree[num].cover = 0;
        }
        if(r <= mid)
            insert(num<<1,s,mid,l,r,val,dir);
        else
        {
            if(l > mid)
                insert(num<<1|1,mid + 1,e,l,r,val,dir);
            else
            {
                insert(num<<1,s,mid,l,mid,val,dir);
                insert(num<<1|1,mid + 1,e,mid + 1,r,val,dir);
            }
        }
        tree[num].len = tree[num<<1].len + tree[num<<1|1].len;
    }
}stx,sty;
int getx(int x)
{
    int l,r,mid;
    l = 1;r = nx;
    while(l <= r)
    {
        mid = (l + r)>>1;
        if(hx[mid] == x)
            return mid;
        else
        {
            if(hx[mid] > x)
                r = mid - 1;
            else
                l = mid + 1;
        }
    }
}
int gety(int x)
{
    int l,r,mid;
    l = 1;r = ny;
    while(l <= r)
    {
        mid = (l + r)>>1;
        if(hy[mid] == x)
            return mid;
        else
        {
            if(hy[mid] > x)
                r = mid - 1;
            else
                l = mid + 1;
        }
    }
}

int main()
{
    int i,j;
    int x1,x2,y1,y2;
    while(scanf("%d",&w) != EOF)
    {
        scanf("%d%d%d",&h,&n,&m);
        w ++;h ++;
        nx = ny = 1;
        linex[1].a = liney[1].a = 1;
        linex[1].b = liney[1].b = m;
        linex[1].c = h;liney[1].c = w;
        for(i = 2;i <= n + n;i += 2)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            x2 ++;y2 ++;
            linex[i].a = x1;linex[i].b = y1;linex[i].c = y2 + m - 1;linex[i].d = 1;
            if(linex[i].c > h)
                linex[i].c = h;
            linex[i + 1].a = x2;linex[i + 1].b = y1;linex[i + 1].c = y2 + m - 1;linex[i + 1].d = -1;
            if(linex[i + 1].c > h)
                linex[i + 1].c = h;
            liney[i].a = y1;liney[i].b = x1;liney[i].c = x2 + m - 1;liney[i].d = 1;
            if(liney[i].c  > w)
                liney[i].c = w;
            liney[i + 1].a = y2;liney[i + 1].b = x1;liney[i + 1].c = x2 + m - 1;liney[i + 1].d = -1;
            if(liney[i + 1].c > w)
                liney[i + 1].c = w;
            hx[nx ++] = x1;hx[nx ++] = x2;hx[nx ++] = liney[i].c;
            hy[ny ++] = y1;hy[ny ++] = y2;hy[ny ++] = linex[i].c;
        }
        linex[i].a = w;liney[i].a = h;
        linex[i].b = liney[i].b = m;
        linex[i].c = h;
        liney[i].c = w;
        hx[nx ++] = 1;hx[nx ++] = w;hx[nx ++] = m;
        hy[ny ++] = 1;hy[ny ++] = h;hy[ny ++] = m;
        sort(linex + 1,linex + n + n + 3,cmp);
        sort(liney + 1,liney + n + n + 3,cmp);
        sort(hx + 1,hx + nx);
        sort(hy + 1,hy + ny);
        j = nx;
        nx = ny = 2;
        for(i = 2;i < j;i ++)
        {
            if(hx[i] != hx[i - 1])
                hx[nx ++] = hx[i];
            if(hy[i] != hy[i - 1])
                hy[ny ++] = hy[i];
        }
        nx --;ny --;
        stx.init(1,1,ny);
        sty.init(1,1,nx);
        int l,r;
        l = 1;r = gety(m) - 1;
        if(l <= r)
            stx.insert(1,1,ny,l,r,1000000,0);
        r = getx(m) - 1;
        if(l <= r)
            sty.insert(1,1,nx,l,r,1000000,1);
        __int64 ans = 0;
        for(i = 2;i <= n + n + 2;i ++)
        {
            ans += (__int64)(linex[i].a - linex[i - 1].a) * (h - 1 - stx.tree[1].len);
            ans += (__int64)(liney[i].a - liney[i - 1].a) * (w - 1 - sty.tree[1].len);
            l = gety(linex[i].b);r = gety(linex[i].c) - 1;
            stx.insert(1,1,ny,l,r,linex[i].d,0);
            l = getx(liney[i].b);r = getx(liney[i].c) - 1;
            sty.insert(1,1,nx,l,r,liney[i].d,1);
        }
        if(m == 1)
            ans /= 2;
        printf("%I64d\n",ans);
    }
    return 0;
}
/*
3 3 1 2
2 2 2 2
3 3 1 3
2 2 2 2
2 3 2 2
1 1 1 1
2 3 2 3
3 3 0 2
3 3 0 1
3 3 1 1
2 2 2 2
5 4 1 2
2 2 3 3
5 4 5 2
1 1 1 2
2 3 2 4
3 1 3 2
4 3 4 4
5 1 5 2
4 4 2 2
2 1 3 2
2 3 3 4
*/
//1453MS	12812K

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值