链接
https://www.luogu.org/problem/show?pid=3616
题解
orz模hhf大佬。
露出水面的部分=露出水面的石头个数-自己和前一个都露出水面的个数。
离散,然后把每块石头的高度丢进权值树状数组(+1);每一个和前一个取min,丢进同一个树状数组(-1),一次询问,直接看大于当前数的和是多少就好了。
代码
//树状数组
#include <cstdio>
#include <algorithm>
#define maxn 1000000
#define lowbit(x) (x&-x)
using namespace std;
int ta[maxn], tmp[maxn], q[maxn][3], N, a[maxn], tot, M;
inline int ls(int x){return lower_bound(tmp+1,tmp+tot+1,x)-tmp;}
inline void add(int pos, int v){for(;pos<=tot;pos+=lowbit(pos))ta[pos]+=v;}
inline int sum(int pos)
{
int ans=0;
for(;pos;pos-=lowbit(pos))ans+=ta[pos];
return ans;
}
int main()
{
int i;
scanf("%d%d",&N,&M);
for(i=1;i<=N;i++)scanf("%d",a+i),tmp[++tot]=a[i];
for(i=1;i<=M;i++)
{
scanf("%d%d",q[i],q[i]+1);
if(q[i][0]==2)scanf("%d",q[i]+2),tmp[++tot]=q[i][2];
tmp[++tot]=q[i][1];
}
sort(tmp+1,tmp+tot+1);
for(i=1;i<=N;i++)add(a[i]=ls(a[i]),1);
for(i=2;i<=N;i++)add(min(a[i],a[i-1]),-1);
for(i=1;i<=M;i++)
{
if(q[i][0]==1)
{
printf("%d\n",1-sum(ls(q[i][1])-1));
}
else
{
q[i][2]=ls(q[i][2]);
add(a[q[i][1]],-1);add(q[i][2],+1);
if(q[i][1]!=1)
add(min(a[q[i][1]],a[q[i][1]-1]),+1),
add(min(q[i][2],a[q[i][1]-1]),-1);
if(q[i][1]!=N)
add(min(a[q[i][1]],a[q[i][1]+1]),+1),
add(min(q[i][2],a[q[i][1]+1]),-1);
a[q[i][1]]=q[i][2];
}
}
return 0;
}