Description
博艾的富金森林公园里有一个长长的富金山脉,山脉是由一块块巨石并列构成的,编号从1到N。每一个巨石有一个海拔高度。而这个山脉又在一个盆地中,盆地里可能会积水,积水也有一个海拔高度,所有严格低于这个海拔高度的巨石,就会在水面下隐藏。
由于地壳运动,巨石的海拔高度可能会随时变化,每次一块的巨石会变成新的海拔高度。当然,水面的高度也会随时发生变化。
因为有这样奇妙的地质奇观,吸引了很多游客来游玩。uim作为一个游客,可以告诉你此时水位海拔,你得告诉他,能看到有几个连续露出水面的部分。(与水面持平我们也认为是露出)
题解
考虑暴力,询问的时候 O(N) 扫一遍数组,只要相邻的两个前一个更小并且洪水的高度满足 hi−1<H≤hi 就直接 ans++ 。那么,我们会发现,每次修改时可能对答案产生影响的地方只可能是与修改的地方相邻的土地。并且,在 (hi−1,hi] 这段区间内的询问都会加一,这是典型的区间加和单点询问,可以用树状数组或是线段树,同时不要忘记在修改修改前要先把当前位置在修改以前对答案的贡献消掉。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 400006
using namespace std;
inline char nc(){
static char buf[100000],*i=buf,*j=buf;
return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
int sum=0;char ch=nc();
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
struct data{
int l,r,tag,num;
void add(int x){tag+=x;num+=x;}
}tree[maxn*4];
struct init{
int k,x,y,yy,id;
bool operator <(const init&b)const{return id<b.id;}
}a[maxn*2];
int n,tet;
void build(int p,int l,int r){
tree[p].l=l;tree[p].r=r;
if(l>=r)return;
int mid=(l+r)>>1;
build(p<<1,l,mid);build(p<<1|1,mid+1,r);
}
void pushdown(int p){
if(!tree[p].tag)return;
tree[p<<1].add(tree[p].tag);
tree[p<<1|1].add(tree[p].tag);
tree[p].tag=0;
}
void update(int p,int l,int r,int x){
if(tree[p].l>r||tree[p].r<l)return;
if(l<=tree[p].l&&r>=tree[p].r){
tree[p].add(x);return;
}
pushdown(p);
update(p<<1,l,r,x);update(p<<1|1,l,r,x);
}
int query(int p,int x){
if(tree[p].l>x||tree[p].r<x)return 0;
if(tree[p].l==tree[p].r)return tree[p].num;
pushdown(p);
return query(p<<1,x)+query(p<<1|1,x);
}
bool cmp(init x,init y){return x.y<y.y;}
int main(){
n=_read();tet=_read();
for(int i=1;i<=n;i++)a[i].y=_read(),a[i].id=i;
for(int i=n+1;i<=n+tet;i++){
a[i].k=_read();
if(a[i].k==2)a[i].x=_read(),a[i].y=_read();
else a[i].y=_read();
a[i].id=i;
}
sort(a+1,a+1+n+tet,cmp);a[1].yy=1;
for(int i=2;i<=tet+n;i++) if(a[i].y!=a[i-1].y)a[i].yy=a[i-1].yy+1;
else a[i].yy=a[i-1].yy;
build(1,1,a[tet+n].yy);
sort(a+1,a+1+tet+n);a[0].yy=0;
for(int i=1;i<=n;i++) if(a[i-1].yy<a[i].yy)update(1,a[i-1].yy+1,a[i].yy,1);
for(int i=n+1;i<=n+tet;i++){
if(a[i].k==2){
int x=a[i].x;
if(a[x-1].yy<a[x].yy)update(1,a[x-1].yy+1,a[x].yy,-1);
if(x!=n&&a[x].yy<a[x+1].yy)update(1,a[x].yy+1,a[x+1].yy,-1);
a[x].yy=a[i].yy;
if(a[x-1].yy<a[x].yy)update(1,a[x-1].yy+1,a[x].yy,1);
if(x!=n&&a[x].yy<a[x+1].yy)update(1,a[x].yy+1,a[x+1].yy,1);
}else printf("%d\n",query(1,a[i].yy));
}
return 0;
}