牛客-小石的海岛之旅 (线性联通块)

链接:https://ac.nowcoder.com/acm/contest/949/C
来源:牛客网

题目描述

暑假到了,小石和小雨到海岛上玩。
从水平方向看海岛可以看成 n个小块,每一个小块都有一个高度hi
水位一开始为 0,随着水位的上升,海岛分成了若干块。
现在有 m 个询问,求当水位为ai 时,海岛会分成多少块。
 

输入描述:

第一行输入两个正整数n,m,分别表示海岛小块个数和询问个数。
第二行输入 n 个整数 hi,表示每一块的高度。
第三行输入 m个整数 ai,表示每一个询问,保证输入的 ai 单调递增。

输出描述:

共 m 行,分别对应m个询问的答案。
示例1

输入

复制
7 3
1 2 3 1 2 1 3
1 2 3

输出

复制
3
2
0

说明

当水位高度为 1 时,岛屿被分成 3 块,2 3;2;3

当水位高度为 2 时,岛屿被分成 2 块:3;3 。

当水位高度为 3 时,岛屿全部被淹没,剩余 0 块 。

备注:

1≤n,m≤103,1≤hi≤10^9,1≤ai<ai+1≤10^91 

分析: 数据量有点小,暴力枚举O(n*m) 当m=10^4 就会爆炸啊
怎么办呢, 对于这种问题其实union-find可以做,但对于这种线性的看两边就好了
先把石头安高度排序, 如果某块石头被淹, 就看它两端石头是否被淹, 都被淹块减一,都没有被淹块加一
复杂度O(nlogn)

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+7;
struct node {
    int h;
    int id;
    bool operator<(const node& a) const {
        return h<a.h;
    } 
};
node s[N],q[N];
int n,m;
int ans[N]; bool vis[N];
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for (int i=1;i<=n;i++) {
        cin>>s[i].h;
        s[i].id=i;
    }
    sort (s+1,s+1+n);
    for (int i=1;i<=m;i++) {
        cin>>q[i].h;
        q[i].id=i;
    }
    sort (q+1,q+1+m);  // 即使输入的查询无序也可以离线做
    int sum=1,j=1;
    for (int i=1;i<=m;i++) {
        while (j<=n&&s[j].h<=q[i].h) {
            int id=s[j++].id;
            if (id==1) sum-=vis[2];
            else if (id==n) sum-=vis[n-1];
            else if (vis[id-1]&&vis[id+1]) sum--;
            else if (!vis[id-1]&&!vis[id+1]) sum++;
            vis[id]=1;
        }
        ans[q[i].id]=sum;
    }
    for (int i=1;i<=m;i++)
        cout<<ans[i]<<"
";
    return 0;

}


原文地址:https://www.cnblogs.com/xidian-mao/p/11393737.html