hdu 4429 Split the Rectangle(lca+二叉树)

Split the Rectangle

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


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

题意:

给定一个矩形,并给出n条线段,每个线段会将空白的矩形划分成两块。现给出两个点,问通过删除线段的方法能让两个点在同一块空白矩形的时候最多能剩多少个空白矩形?

思路:

每次线段划分矩形的时候都会划分成左右两块矩形。于是可以将这个二维的图建成一棵树。保存线段划分成左右子图的状态。在询问时,寻找他们的最近公共祖先。然后答案就是num[0]-num[pos]+1。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=2005;
int num[maxn];//表示子图的数量
struct rec
{
    int lx,ly,rx,ry;
    int fath,lson,rson,dep;
}q[maxn];
int find(int x,int y)
{
    int r=0,t;
    while(1)
    {
        if(q[r].lson==0) return r;
        t=q[r].lson;
        if(x>=q[t].lx&&x<=q[t].rx&&y>=q[t].ly&&y<=q[t].ry)
            r=t;
        else
            r=q[r].rson;
    }
}
int get_num(int u)
{
    num[u]=0;
    if(q[u].lson==0) return num[u]=1;
    else
    {
        num[u]+=get_num(q[u].lson);
        num[u]+=get_num(q[u].rson);
    }
    return num[u];
}
int lca(int lx,int ly,int rx,int ry)
{
    int a=find(lx,ly);
    int b=find(rx,ry);
    while(a!=b)
    {
        if(q[a].dep<q[b].dep)
            b=q[b].fath;
        else if(q[a].dep>q[b].dep)
            a=q[a].fath;
        else
        {
            a=q[a].fath;
            b=q[b].fath;
        }
    }
    return a;
}
int main()
{
    int lx,ly,rx,ry,n,w,now;
    while(~scanf("%d%d%d%d",&lx,&ly,&rx,&ry))
    {
        now=0;
        q[now++]=(rec){lx,ly,rx,ry,-1,0,0,0};
        scanf("%d%d",&n,&w);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&lx,&ly,&rx,&ry);
            if(lx>rx) swap(lx,rx);
            if(ly>ry) swap(ly,ry);
            int mx=(lx+rx)/2,my=(ly+ry)/2;
            int pos=find(mx,my);
            int dep=q[pos].dep;
            q[pos].lson=now;
            q[now]=(rec){q[pos].lx,q[pos].ly,rx,ry,pos,0,0,dep+1};
            now++;
            q[pos].rson=now;
            q[now]=(rec){lx,ly,q[pos].rx,q[pos].ry,pos,0,0,dep+1};
            now++;
        }
        get_num(0);
        for(int i=1;i<=w;i++)
        {
            scanf("%d%d%d%d",&lx,&ly,&rx,&ry);
            int pos=lca(lx,ly,rx,ry);
            printf("%d\n",num[0]-num[pos]+1);
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值