POJ 3347 Kadj Squares (几何+线段树)

题意:

按图中所示的方式摆放正方形。输出那些正方形从上往下看得到的正方形。

题解:1:由于所有线段都成45/135度角的关系,将所有数据大sqrt(2)倍,便可以当做整数来处理。2:用线段树处理覆盖的时候,由于只能处理整点,下面的情况需要注意

即第3只有最左边的一点可以看到。但是第2却把该点标为2,这样一来得到的结果就是3看不到。为避免这种情况发生,可以将每一个正方形的左右两点都乘以2,然后右边的点再减去1.(类似于开区间闭区间的处理)

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;

#define L(u) ((u)<<1)
#define R(u) ((u)<<1|1)

struct Square
{
    int b, l, r, len, id, flag;
} s[500];

struct NODE
{
    int l, r, flag;
} node[10000];

bool mark[500];

void build ( int u, int l, int r )
{
    node[u].l = l;
    node[u].r = r;
    node[u].flag = 0;
    if ( l == r ) return;
    int mid = ( l + r ) >> 1;
    build (L(u), l, mid );
    build (R(u), mid+1, r );
}

void update ( int u, int l, int r, int f )
{
    if ( node[u].l == l && node[u].r == r )
    {
        node[u].flag = f; return;
    }

    if ( node[u].flag != 0 )
    {
        node[L(u)].flag = node[u].flag;
        node[R(u)].flag = node[u].flag;
        node[u].flag = 0;
    }

    int mid = ( node[u].l + node[u].r ) >> 1;
    if ( r <= mid )
        update ( L(u), l, r, f );
    else if ( l > mid )
        update ( R(u), l, r, f );
    else
    {
        update ( L(u), l, mid, f );
        update ( R(u), mid+1, r, f );
    }
}

void query ( int u )
{
    if ( node[u].flag != 0 )
    {
        mark[node[u].flag] = true;
        return;
    }
    if ( node[u].l == node[u].r ) return;
    query(L(u)); query(R(u));
}

bool cmp ( const Square & a, const Square & b )
{
    return a.len <= b.len;
}

int main()
{
    int n;
    while ( scanf("%d",&n) && n )
    {
        int i, j, tmp, t = 0;
        for ( i = 1; i <= n; i++ )
        {
            scanf("%d",&s[i].len);
            s[i].id = i; tmp = 0;
            if ( i == 1 )
                s[i].b = s[i].len;
            else
            {
                for ( j = i - 1; j >= 1; j-- ) //枚举所有i前面的矩形,让第i个矩形与前面的某一个矩形紧凑的靠在一起
                {
                    if ( s[i].len > s[j].len )
                        tmp = max(tmp, s[j].b+s[j].len*2);
                    else { tmp = max(tmp, s[j].b+s[i].len*2); break;}
                }
                if ( j < 1 && s[i].len >= tmp ) s[i].b = s[i].len;
                else s[i].b = tmp;
            }

            s[i].l = ( s[i].b - s[i].len ) * 2;  //注意!!!
            s[i].r = ( s[i].b + s[i].len ) * 2 - 1; //!!!
            t = max(s[i].r,t);
        }

        sort(s+1,s+1+n,cmp);
        build ( 1, 0, t );
        memset(mark,0,sizeof(mark));

        for ( i = 1; i <= n; i++ )
            update ( 1, s[i].l, s[i].r, s[i].id );

        query ( 1 );
        for ( i = 1; i <= n; i++ )
            if ( mark[i] ) printf("%d ", i);
        printf("\n");
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值