快晴

导航

NEUOJ 20校赛复现 Just Dig It 排序/离散化

我最喜欢的彩爷镇楼。。

真的是大水题一道,至于为什么我想写这道题的题解,是因为我lyd的离散化习题不会做(拿题练离散化

以前离散化的题几乎都被我拿map和unordered_map水过去了,导致我离散化特别不上手(

题解如下,,,

题干:

博士来到了一片大平原寻宝。该平原长为n,宽为m。博士把这片平原划分成n*m块1*1的区域。经过探测发现,这片平原存在着k处宝藏。博士想将所有宝藏都挖出来。

初始时该平原每一块区域的高度均为0。宝藏的位置信息由x,y,d三个数字决定,代表该宝藏在(x,y)区域深度为d(即高度为-d)的位置,每个宝藏的体积均为1。为了避免发生塌方事故,博士一次只能在某个区域竖直往下挖,也就是说,博士每次只能挖动每个区域中最高的部分。

博士每次挖动只能挖开体积为1的泥土或宝藏,并且耗费1点体力,相应地,该区域的高度减1。只有挖动操作消耗体力。如果博士挖出来宝藏,将会立刻有直升机将宝藏运离大平原。如果挖出的是泥土,博士就必须将其堆在大平原内任意一个区域上,选择堆放的位置可以是任意的,堆放泥土后该区域的高度增加1。每个区域的高度不受限制。

现在博士已经开始挖宝藏了,请你告诉博士,最少需要耗费多少点体力才能挖出所有的宝藏。

Input

       输入有若干组数据。

       对于每一组数据,第一行输入三个整数n,m,k(n>0,m>0,2<=n*m<=1e6,k>=0)。接下来的k行,每行输入三个整数x,y,d(1<=x<=n,1<=y<=m,1<=d<=1e9),代表该宝藏在区域(x,y)深度为d(即高度为-d)的位置上。每组数据内的宝藏位置保证两两互不相同。

       数据保证每组数据的k之和不超过5e5。

我们一看,只要判断一下不同坐标种数大小是否等于n*m,如果不等于,我们直接挖,如果等于,我们第一个挑挖泥土最少的挖。

然后我们愉快的开了map[1000010][1000010],然后就正中出题人下怀了。

如果我们开map[1000010][1000010],空间时间双双爆炸。

因此我们要对map即每一个点离散化。

所谓离散化就是只记录需要的信息,抛弃不需要的信息。

离散化就是换一种信息存储的方式而已(个人还没学多少,理解仅限于此

由题,x与y的数据范围有1e6那么大,如果存在一个

99999 99999 1

的数据,无疑我们开一个map[1000010][1000010]是十分浪费的。

算法具体如下:

时间复杂度:O(n*logn)

空间复杂度:O(n);

(注意离散化大多都要去重(本题很巧的也要去重(记得开long long

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
//bb代表原始点,rb代表离散化后的点
struct Box { int x, y; ll w, tot=1; }bb[maxn],rb[maxn]; inline ll max(ll a, ll b) {return a > b ? a : b;} inline ll min(ll a, ll b) { return a < b ? a : b; } int cmp(Box A, Box B) { if (A.x != B.x) return A.x < B.x; return A.y < B.y; } int main() { int n, m, k; while (scanf("%d%d%d",&n,&m,&k)!=EOF) { int rcnt = 0; for (int i = 1;i <= k;++i) { scanf("%d%d%lld", &bb[i].x,&bb[i].y,&bb[i].w); }
     //离散化要一般都要经过排序得到一个有序序列(也方便以后二分查找) sort(bb
+ 1, bb + 1 + k, cmp); ll tot = 0, cnt = 0, minn = 1e9;
     //离散化开始
for (int i = 1;i <= k;++i) {
       //去重
if (bb[i].x == bb[i - 1].x&&bb[i].y == bb[i - 1].y) ++rb[rcnt].tot, rb[rcnt].w = max(rb[rcnt].w, bb[i].w); else rb[++rcnt] = bb[i]; }//离散化结束 for (int i = 1;i <= rcnt;++i) { minn = min(minn, rb[i].w-rb[i].tot); tot += rb[i].w; } if (n*m == rcnt)printf("%lld\n", tot - minn); else printf("%lld\n", tot); } return 0; }

因为我不会对拍,而且题目已经end了所以我测试不了,不知道能不能AC(虽然大样例确实过了

posted on 2021-05-14 00:07  快晴  阅读(110)  评论(0编辑  收藏  举报