题目:点击打开链接(需校园网)
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");
}
}