有N个岛连在一起形成了一个大的岛屿,如果海平面上升超过某些岛的高度时,则这个岛会被淹没。原本的大岛屿则会分为多个小岛屿,如果海平面一直上升,则所有岛都会被淹没在水下。
给出N个岛的高度。然后有Q个查询,每个查询给出一个海平面的高度H,问当海平面高度达到H时,海上共有多少个岛屿。例如:
岛屿的高度为:{2, 1, 3, 2, 3}, 查询为:{0, 1, 3, 2}。
当海面高度为0时,所有的岛形成了1个岛屿。
当海面高度为1时,岛1会被淹没,总共有2个岛屿{2} {3, 2, 3}。
当海面高度为3时,所有岛都会被淹没,总共0个岛屿。
当海面高度为2时,岛0, 1, 3会被淹没,总共有2个岛屿{3} {3}。
Input
第1行:2个数N, Q中间用空格分隔,其中N为岛的数量,Q为查询的数量(1 <= N, Q <= 50000)。 第2 - N + 1行,每行1个数,对应N个岛屿的高度(1 <= A[i] <= 10^9)。 第N + 2 - N + Q + 1行,每行一个数,对应查询的海平面高度(1 <= Q[i] <= 10^9)。
OutPut
输出共Q行,对应每个查询的岛屿数量。
Input示例
5 4 2 1 3 2 3 0 1 3 2
Output示例
1 2 0 2
解题思路:
很显然我们应该按照查询高度从小到大的顺序来进行处理,离线处理所有的查询。首先对于当前的查询深度,我们只需要处理当前还未处理的元素中高度小于等于当前的查询高度的点,将它们设置为淹没,来更新连通区域的个数。假设当前第i个点被淹没,则连通区域的增加与减少与i-1,i+1这两个节点有关,如果这两个节点在这之前没有被淹没则连通区域数增加1,如果仅有一个点被淹没,则连通区域的数目是不变的,如果i-1,i+1这两个点在之前已经被淹没,则当前的点单独为一个连通区域,这样淹没后连通区域的个数减少1.由于每次我们总是处理符合条件高度范围内的节点,而高度范围为10^9,高度个数仅为10^5,因此我们首先进行离散化处理,复杂度O(nlogn),其余操作的复杂度均是线性的。
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <vector> #include <queue> #include <set> #include <map> #include <algorithm> using namespace std; const int maxn = 50010; const int inf = 0x3f3f3f3f; int h1[maxn], h2[maxn], q1[maxn], q2[maxn]; int ans[maxn]; int N, NN, Q, cnt; int bsearch1(int x) { int l = 0, r = NN - 1, m; while(l <= r) { m = l + (r - l) / 2; if(h2[m] == x) { return m + 1; } else if(h2[m] > x) { r = m - 1; } else { l = m + 1; } } return -1; } int bsearch2(int x) { int l = 0, r = NN - 1, m; int ans = -inf; if(h2[0] > x) return 0; while(l <= r) { m = l + (r - l) / 2; if(h2[m] <= x) { l = m + 1; ans = max(ans, m); } else { r = m - 1; } } return ans + 1; } vector<int> vec[maxn]; bool mark[maxn]; int main() { //freopen("aa.in", "r", stdin); cnt = 1; scanf("%d %d", &N, &Q); for(int i = 0; i < N; ++i) { scanf("%d", &h1[i]); h2[i] = h1[i]; } sort(h2, h2 + N); NN = unique(h2, h2 + N) - h2; for(int i = 0; i < N; ++i) { h1[i] = bsearch1(h1[i]); vec[h1[i]].push_back(i); } for(int i = 0; i < Q; ++i) { scanf("%d", &q1[i]); q1[i] = bsearch2(q1[i]); q2[i] = q1[i]; } sort(q2, q2 + Q); /* for(int i = 0; i < N; ++i) { printf("%d ", h1[i]); } printf("\n"); for(int i = 0; i < Q; ++i) { printf("%d ", q1[i]); } printf("\n"); */ memset(ans, -1, sizeof(ans)); memset(mark, true, sizeof(mark)); for(int i = 0; i < Q; ++i) { if(ans[q2[i]] != -1) continue; int s = 1; if(i > 0) s = q2[i-1] + 1; for(int k = s; k <= q2[i]; ++k) { int size = vec[k].size(); for(int j = 0; j < size; ++j) { int id = vec[k][j]; mark[id] = false; int t_cnt = 0; if(id - 1 >= 0 && mark[id-1]) t_cnt++; if(id + 1 < N && mark[id+1]) t_cnt++; if(t_cnt == 2) { cnt++; } else if(t_cnt == 0) { cnt--; } } } ans[q2[i]] = cnt; } for(int i = 0; i < Q; ++i) { printf("%d\n", ans[q1[i]]); } return 0; } /* // TLE 代码 struct Query { int h, id; Query() { } Query(int t_h, int t_id) : h(t_h), id(t_id) { } bool operator < (const Query &q) const { return h < q.h; } }query[maxn]; vector< pair<int, int> > vec[2]; int height[maxn]; int ans[maxn]; int N, Q, id, cur_min_h; int main() { //freopen("aa.in", "r", stdin); id = 0; cur_min_h = inf; scanf("%d %d", &N, &Q); for(int i = 0; i < N; ++i) { scanf("%d", &height[i]); cur_min_h = min(cur_min_h, height[i]); } for(int i = 0; i < Q; ++i) { query[i].id = i; scanf("%d", &query[i].h); } sort(query, query + Q); vec[id].push_back(make_pair(0, N-1)); for(int i = 0; i < Q; ++i) { int th = query[i].h; if(cur_min_h > th) { if(i == 0) { ans[query[i].id] = 1; } else { ans[query[i].id] = ans[query[i-1].id]; } continue; } cur_min_h = inf; int size = vec[id].size(); for(int j = 0; j < size; ++j) { int x = vec[id][j].first; int y = vec[id][j].second; int s = -1, e = -1; //printf("TTest: %d %d\n", x, y); for(int k = x; k <= y; ++k) { if(height[k] <= th) { if(s != -1) { //printf("Test: %d %d\n", s, e); vec[id^1].push_back(make_pair(s, e)); s = -1; e = -1; } } else { if(s == -1) { s = k; } e = k; cur_min_h = min(cur_min_h, height[k]); } } if(s != -1) { vec[id^1].push_back(make_pair(s, e)); } } ans[query[i].id] = vec[id^1].size(); vec[id].clear(); id ^= 1; } for(int i = 0; i < Q; ++i) { printf("%d\n", ans[i]); } return 0; } */