[HDU 4429]Split the Rectangle[LCA][二叉树]

题目链接: [HDU 4429]Split the Rectangle[LCA][二叉树]

题意分析:

Alice和Bob玩游戏,初始时Bob会在左下角坐标为XL,YL,右上角坐标为XR,YR的矩形中绘制线段,给出线段的首尾两个端点,保证每条线段都能将线段所在的矩形划分成更小的两个矩形,问:现在Bob给出Q个查询,每次查询包含两个点,要求删除一些边使得这两个点在同一个矩形中,删除边后必须保证整个图都是矩形,而不存在其它形状的图形,问删除这些边之后最多剩多少矩形?

解题思路:

每个线段都能把矩形切分成更小的两个矩形。二叉树呀= =。把树建完之后,用num[i]数组把i结点的所有子节点个数保存下来,那么每次查询其实就是问这两个点所在的矩形的公共祖先的子结点有多少个?总的答案就是总共的矩形数-祖先的子节点数+1。加1是因为祖先的子节点把自己算进去了。

个人感受:

妙~

具体代码如下:

#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
using namespace std;

const int INF = 0x7f7f7f7f;
const int MAXN = 2005;

struct Node {
    int lx, ly, rx, ry;
    int p, lson, rson, dep;
}node[MAXN];

int num[MAXN]; // 子节点个数

// 确定当前线段在哪个父节点下
int getPos(int p, int x, int y) {
    if (node[p].lson == 0) return p;
    int l = node[p].lson;
    if (node[l].lx <= x && x <= node[l].rx && node[l].ly <= y && y <= node[l].ry)
        return getPos(l, x, y);
    else return getPos(node[p].rson, x, y);
}

// 计算子节点个数
int getSon(int u) {
    num[u] = 0;
    if (node[u].lson == 0) return num[u] = 1;
    else {
        num[u] += getSon(node[u].lson) + getSon(node[u].rson);
    }
    return num[u];
}

int main()
{
    #ifdef LOCAL
    freopen("C:\\Users\\apple\\Desktop\\in.txt", "r", stdin);
    #endif
    int lx, ly, rx, ry, n, q;
    while (~scanf("%d%d%d%d", &lx, &ly, &rx, &ry)) {
        scanf("%d%d", &n, &q);
        int rt = 0, cnt = 1;
        node[rt] = (Node){lx, ly, rx, ry, -1, 0, 0, 0};

        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);
            int mx = (lx + rx) / 2, my = (ly + ry) / 2;

            int pos = getPos(0, mx, my);
            Node &t = node[pos];
            t.lson = cnt;
            node[cnt++] = (Node){t.lx, t.ly, rx, ry, pos, 0, 0, t.dep + 1};
            t.rson = cnt;
            node[cnt++] = (Node){lx, ly, t.rx, t.ry, pos, 0, 0, t.dep + 1};
        }

        getSon(0);

        while (q --) {
            scanf("%d%d%d%d", &lx, &ly, &rx, &ry);
            int p1 = getPos(0, lx, ly), p2 = getPos(0, rx, ry);
            while (p1 != p2) {
                if (node[p1].dep < node[p2].dep) p2 = node[p2].p;
                else if (node[p1].dep > node[p2].dep) p1 = node[p1].p;
                else {
                    p1 = node[p1].p;
                    p2 = node[p2].p;
                }
            }
            printf("%d\n", n + 1 - num[p1] + 1);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值