题目大意:
校门外栽满了不同高度的树,每一次询问是 如果砍掉所有高度不超过q的树,那么还有多少个连续的块。
思路分析:
记录左连续和 右连续和 用来维护区间的连续块的数量。
即
seg[num] = seg[num<<1]+seg[num<<1|1] ;
如果中间部分连起来 那么减一即可。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define maxn 50005
#define lson num<<1,s,mid
#define rson num<<1|1,mid+1,e
#define mid ((s+e)>>1)
using namespace std;
int lsum[maxn<<2],rsum[maxn<<2],seg[maxn<<2];
struct tree{
int height;
int pos;
bool operator < (const tree &cmp)const{
return height<cmp.height;
}
}save[maxn];
struct Ans{
int index;
int query;
int ans;
bool operator < (const Ans & cmp)const{
return query<cmp.query;
}
}prt[maxn];
bool cmp_id(Ans a,Ans b){
return a.index<b.index;
}
void pushup(int num,int s,int e){
lsum[num]=lsum[num<<1];
if(lsum[num]==mid-s+1)lsum[num]+=lsum[num<<1|1];
rsum[num]=rsum[num<<1|1];
if(rsum[num]==e-mid)rsum[num]+=rsum[num<<1];
seg[num]=seg[num<<1]+seg[num<<1|1];
if(rsum[num<<1] && lsum[num<<1|1])seg[num]--;
}
void build(int num,int s,int e){
if(s==e){
lsum[num]=rsum[num]=seg[num]=1;
return;
}
build(lson);
build(rson);
pushup(num,s,e);
}
void update(int num,int s,int e,int pos){
if(s==e){
lsum[num]--,rsum[num]--,seg[num]--;
return;
}
if(pos<=mid)update(lson,pos);
else update(rson,pos);
pushup(num,s,e);
}
int main()
{
int n,q;
while(scanf("%d%d",&n,&q)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&save[i].height);
save[i].pos=i;
}
sort(save+1,save+1+n);
for(int i=1;i<=q;i++){
scanf("%d",&prt[i].query);
prt[i].index=i;
}
sort(prt+1,prt+1+q);
build(1,1,n);
int dex = 1;
for(int i=1;i<=q;i++){
while(save[dex].height<=prt[i].query && dex<=n){
update(1,1,n,save[dex].pos);
dex++;
}
prt[i].ans = seg[1];
}
sort(prt+1,prt+1+q,cmp_id);
for(int i=1;i<=q;i++){
printf("%d\n",prt[i].ans);
}
}
return 0;
}