Split the Rectangle  HDU - 4429

Split the Rectangle

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 717    Accepted Submission(s): 256


Problem Description
Alice comes up with a new game and wants to play with Bob.
There is one rectangle on the paper initially, we define its lower-left corner's coordinate is (x L, y L) and upper-right corner's coordinate is (x R, y R).
Bob has executed the step as description below N times:
Bob should select one empty rectangle. If the rectangle is the initial one or is split by one vertical segment, he should split it into two parts by drawing one horizontal segment; otherwise he should split the rectangle into two parts by drawing one vertical segment. An empty rectangle means there is no segment in this rectangle except its only four boundary segments.
You should pay attention that there are only two kinds segments: vertical segment and horizontal segment.
Now Bob has several queries. In each query, Bob selects two target points in the paper. (You can assume that all given target points are always located inside the initial rectangle and not in any drawing segments.) He wants Alice to answer the question as soon as possible: Alice can erase several existing segments, and make two target points in one empty rectangle, and she should answer how many empty rectangles at most would be left at last.
But there are some restrictions: Alice cannot erase segments of the initial rectangle (the (x L, y L) to (x R, y R) one), she can only erase segments drew by Bob; if Alice want to erase one segment, both sides of the segment must be empty rectangles, and after erase it, the two empty rectangles must combine to one bigger empty rectangle; if erasing an existing segment will lead to a disconnected graph, the operation is forbidden.

 

Input
There are multiple test cases.
The first line contains four integers x L, y L, x R, y R indicating the coordinates of the lower-left corner and the upper-right corner of the initial huge rectangle respectively. (-100,000 <= x L, y L, x R, y R <= 100,000, x L< x R, y L< y R)
The next line contains two integers N and Q. (1 <= N, Q <= 1000)
The next N lines each line contains four integers x 1, y 1, x 2, y 2 indicating the coordinates of two endpoints of one drawing segments. (-100,000 <= x 1, y 1, x 2, y 2 <= 100,000, x 1=x 2 | y 1=y 2)
The next Q lines each line contains four integers x A, y A, x B, y B indicating the coordinates of two target points in this query. (-100,000 <= x A, y A, x B, y B <= 100,000).

 

Output
For each test case, output Q lines, output the answer of each query in each line.
 

Sample Input
  
  
-10 -10 10 10 5 1 -10 0 10 0 5 -10 5 0 -5 0 -5 10 -5 5 10 5 5 -5 10 -5 0 -3 7 -3 0 0 4 4 3 2 0 2 4 2 2 0 2 2 2 2 2 4 1 1 1 3 1 1 3 1 -10 -10 10 10 3 4 -10 0 10 0 0 -10 0 0 0 0 0 10 -9 -9 -8 -8 -9 -9 -9 9 -9 -9 9 -9 -9 -9 9 9
 

Sample Output
  
  
4 1 3 4 1 3

1

将矩形转化成树 每被一条线分割就生成他的左右儿子

树的节点除了记录左右儿子之外 矩形信息(存左上右下点来表示)

还要记录父节点和深度 用于查询公共祖先。

num数组记录每个节点的子节点数

则n+2-num[公共祖先]就是剩余的矩形数

(因为n+1是总矩形数

然后为了让两个点在同一个矩形里肯定要擦掉他们公共祖先里所有的边

所以减少的矩形数就是num[公共祖先]-1)

      

#include <iostream>
#include<cstdio>
using namespace std;
const int maxn=2005;
int num[maxn];
struct node
{
    int lx,ly,rx,ry;              //存左上右下
    int f,lson,rson,deep;
}tree[maxn];
int find(int midx,int midy)
{
        int r=0;
        while(1)
        {
            if(tree[r].lson==0)return r;  //是一根线把矩形分成两半 没有左儿子就没有右
            int tmp=tree[r].lson;
        if(midx<=tree[tmp].rx&&midx>=tree[tmp].lx
           &&midy>=tree[tmp].ly&&midy<=tree[tmp].ry)
          r=tmp;
        else
            r=tree[r].rson;
        }
}
int getnum(int r)
{
    num[r]=0;
    if(tree[r].lson==0)return num[r]=1;
    else
    {
        num[r]+=getnum(tree[r].lson);
        num[r]+=getnum(tree[r].rson);
    }
    return num[r];
}
int main()
{
    int lx,ly,rx,ry;
    while(~scanf("%d%d%d%d",&lx,&ly,&rx,&ry))
    {
        int root=0,cur=1;
        tree[root]=node{lx,ly,rx,ry,-1,0,0,0}  ;  //根节点的f设为-1
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d%d",&lx,&ly,&rx,&ry);
            if(lx>rx)swap(lx,rx);
            if(ly>ry)swap(ly,ry);     //zhuyi

            int midx=(lx+rx)/2,midy=(ly+ry)/2;
            int tmp=find(midx,midy);  //找在哪个区域
            int deep=tree[tmp].deep;

            //把分割后的两个矩形保存为左右儿子
            tree[tmp].lson=cur;
            tree[cur]=node{tree[tmp].lx,tree[tmp].ly,rx,ry,tmp,0,0,deep+1};
            cur++;
            tree[tmp].rson=cur;
            tree[cur]=node{lx,ly,tree[tmp].rx,tree[tmp].ry,tmp,0,0,deep+1};
            cur++;
           
        }
        getnum(0);
        

        for(int i=0;i<q;i++)
        {
            scanf("%d%d%d%d",&lx,&ly,&rx,&ry);
            int tmp1=find(lx,ly);
            int tmp2=find(rx,ry);
            while(tmp1!=tmp2)
            {
                if(tree[tmp1].deep<tree[tmp2].deep)tmp2=tree[tmp2].f;         //同一深度
                else if(tree[tmp1].deep>tree[tmp2].deep)tmp1=tree[tmp1].f;
                else
                {
                    tmp1=tree[tmp1].f;
                    tmp2=tree[tmp2].f;
                }
            }
            
        printf("%d\n",n+2-num[tmp1]);
        }
    }
    return 0;
}

      

      

          

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值