洛谷 P1884Overplanting S 离散化+二维差分

题目介绍

题目链接

题目解读

题目很简单,求并区间面积

解题思路

离散化+二维差分

这种题用二维差分可以解决,但是问题在于x,y的值过大,而且还有负数,无法开数组进行差分

可以离散化处理x,y,再进行差分

离散化

离散化:把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。

通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:

原数据:1,999,100000,15;处理后:1,3,4,2;

原数据:{100,200},{20,50000},{1,400};

处理后:{3,4},{2,6},{1,5};

(来自百度百科)

即使每个x,y都不相同,离散化后最多也就是N*4个数,完全可以进行差分解题

AC代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000;
int n;
int x1s[maxn + 1], y1s[maxn + 1], x2s[maxn + 1], y2s[maxn + 1]; //存储坐标
int G[4*maxn + 1][4*maxn + 1];  //二维差分数组
int arr[4 * maxn + 1], listInx = 0;  //存储所有x,y的值
int rest[4 * maxn + 1],restInx = 0; //记录编号对应的数字
map<int, int> toId; //用于获得数字对应的编号
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> x1s[i] >> y1s[i] >> x2s[i] >> y2s[i];
        arr[++listInx] = x1s[i]; //把坐标全添加到arr中
        arr[++listInx] = y1s[i];
        arr[++listInx] = x2s[i];
        arr[++listInx] = y2s[i];
    }
    arr[0] = -1e9;
    sort(arr + 1, arr + listInx + 1); //排序
    for (int i = 1; i <= listInx; i++) {
        if (arr[i] != arr[i - 1]) { //避免重复的值
            rest[++restInx] = arr[i]; //编号restInx的值为arr[i];
            toId[arr[i]] = restInx; //存进map 能够查询数值的编号
        }
    }
    for (int i = 1; i <= n; ++i) {
        int x1 = toId[x1s[i]]; //把x,y都换成对应的编号
        int y1 = toId[y1s[i]];
        int x2 = toId[x2s[i]];
        int y2 = toId[y2s[i]];
        G[x1][y2]++; //二维差分
        G[x2][y2]--; //注意题目有写两个坐标的大小关系,注意选择合适的两个坐标中x和y
        G[x1][y1]--;//这个题求的是点之间的面积,x,y并不需要-1,+1,具体请画图理解
        G[x2][y1]++;
    }
    for (int i = 1; i <= restInx; i++) {
        for (int j = 1; j <= restInx; j++) {
            //得到每个点被覆盖的次数
            G[i][j] += G[i - 1][j] + G[i][j - 1] - G[i - 1][j - 1];
        }
    }
    long long ans = 0;
    for (int i = 1; i <= restInx; i++) {
        for (int j = 1; j <= restInx; j++) {
            if (G[i][j] > 0) { //如果有被覆盖
                //记得把编号还原为原来的坐标再计算
                ans += (long) (rest[j + 1] - rest[j]) * (rest[i + 1] - rest[i]);
            }
        }
    }
    cout << ans << endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值