IMUTOJ 1073 植树(莫队算法)

题目:点击打开链接(需校园网)

1073: 植树

时间限制: 1 Sec   内存限制: 128 MB
提交: 103   解决: 0
[ 提交][ 状态][ 讨论版]

题目描述

为了地球家园的清新美丽,软件班的孩子们去植树了……他们一共栽了N棵树,这些树的高度是不同的,它们的编号分别为1,2,3…N,树的高度都是正整数。现在班主任给同学们提出了问题:在编号L到编号R之间,高度为H的树的数量恰好也为H的一共有多少种?1<=L<=R<=N。

输入

多组输入数据,每组第一行两个正整数N和M,1<=N,M<=100000,以空格分隔,分别代表树的数量以及班主任问题的数量。第二行输入N个正整数分别代表这N棵树的高度h,1<=h<=1000000000,以空格分隔。从第三行开始,每行输入一个班主任的问题,问题参数是两个位置的编号L和R, 1<=L<=R<=N。输入以文件尾结束。

输出

对于每组输入,按顺序输出班主任所有M个问题的答案,每个答案占一行。每一组输出完成后,再输出一个空行。

样例输入

7 2
3 1 2 2 3 3 7
1 7
3 4
10 2
1 2 2 3 3 3 4 4 4 4
1 6
5 10

样例输出

3
1

3
1

莫队算法讲解:https://www.cnblogs.com/CsOH/p/5904430.html

思路:

先写个结构体,加个构造函数,分块。

然后排序,每次询问由上次的结果移动一下左右节点,得到这次的。

特殊处理一下第一个数是1且区间内只有他一个的情况。

#include<bits/stdc++.h>
using namespace std;
const int maxm=100005;
int len;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Query{
    int L, R, ID, block;
    Query(){}
    Query(int l, int r, int ID):L(l), R(r), ID(ID){
        block = l / len;
    }
    bool operator < (const Query rhs) const{
        if(block == rhs. block) return R<rhs.R;
        return block < rhs.block;
    }
}queries[maxm];

int high[maxm],cnt,ans[maxm];

inline void insert(int n){
    high[n]++;
    if(high[n]==n)
        cnt++;
}

inline void erase(int n){
    high[n]--;
    if(high[n]+1==n&&high[n]!=n)
        cnt--;
    if(high[n]==n)
        cnt++;
}

int A[maxm];
queue<int> anss[maxm];

int main(){
    int n, m;
    while(scanf("%d%d",&n,&m)!=EOF){
        cnt=0;
        memset(high,0,sizeof(high));
        len = (int)sqrt(n);
        for(int i = 1; i <= n; i++)
            A[i]=read();
        for(int i = 1; i <= m; i++){
            int l, r;
            l=read(),r=read();
            queries[i] = Query(l, r, i);
        }
        sort(queries + 1, queries + m + 1);
        int L = 1, R = 1;
        high[A[1]] = 1;
        for(int i = 1; i <= m; i++){
            Query &qi = queries[i];
            while(R < qi.R) insert(A[++R]);
            while(L > qi.L) insert(A[--L]);
            while(R > qi.R) erase(A[R--]);
            while(L < qi.L) erase(A[L++]);
            if(high[1]==1&&A[1]==1) cnt++;
            ans[queries[i].ID]=cnt;
        }
        for(int i = 1; i <= m; i++)
            printf("%d\n",ans[i]);
        printf("\n");
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值