富金森林公园
很有意思的一道题,来水一篇:
-
Analysis:
首先,我们对于每一个连通块,都需要找到一个特征值来统计,思考一下就知道它是每个连通块的左或右端点,本文使用左端点来统计。
进而,我们考虑对于每一种高度的答案分开统计,我们用 代表在当前高度下露出水面的石柱,用 表示当前高度下被水淹没的石柱,然后我们思考以下情况:
约定: 轴代表高度, 轴表示石柱:
我们考虑修改操作:对于 ,它的降低显然会对降低后对应的答案造成贡献,具体来说:当石柱 降低时,我们分别考虑所有会变化的值(答案),如果当前 下,减少的那个石柱的左右两边为空,则当前高度下连通块的数量减少 ,否则就增加 ,我们不妨手玩一下:
假设当前 减少到了 那么原图转化为:
我们发现:二维点对 两边均无石柱,因此 中的贡献减一为零,而 的两边均有石柱,因此 中的贡献加一为二。 与 两边一边有石柱,一边没有,那么修改就对当前答案无贡献,因此 与 不变。
到此我们已经找到了规律,我们很容易将其推广到石柱上升时的情况,那么对于以上修改时的三种情况:两边均有,两边均无,一边有一边无。我们就可以分讨实现修改了。
-
Achieve:
数据结构维护一下我们上文提到的 ,既然是高度,当然要离散化。然后,根据上面的手模,每次的答案更新不同,很麻烦,如何避免?我们考虑每次在修改前,将本次修改影响的答案区间贡献减一,再正常操作,不明白?我们再来手玩一下:
还是上面我们提到的情况:将 降低至 ,因为修改之前 的高度 小于 ,所以我们先将 即 到 的区间减一消除影响,再将 修改至 高度,此时 的高度小于 ,能产生新的左端点,因此 即 到 答案区间加一。至此, 和 的影响抵消,我们完成了想要实现的修改操作。
至于为什么区间修改时,要将左高度加一,这是因为本文选用左端点统计答案,做高度本身就能成为一个左端点。
-
Code:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=400005;
struct node{
int h,id;
bool operator <(const node &b)const
{return h<b.h;}
}a[N<<1];
int h[N<<1],x[N<<1],k[N<<1];
int n,m,mx;
namespace TREE{
int dat[N<<2],tag[N<<2];
void pushdown(int pos){
if(!tag[pos]) return;
int lson=pos<<1,rson=pos<<1|1;
dat[lson]+=tag[pos],dat[rson]+=tag[pos];
tag[lson]+=tag[pos],tag[rson]+=tag[pos];
tag[pos]=0;
}
void modify(int pos,int l,int r,int ql,int qr,int x){
if(ql<=l&&qr>=r){
dat[pos]+=x,tag[pos]+=x;return;
}
pushdown(pos);
int mid=(l+r)>>1;
if(ql<=mid) modify(pos<<1,l,mid,ql,qr,x);
if(qr>mid) modify(pos<<1|1,mid+1,r,ql,qr,x);
}
int query(int pos,int l,int r,int x){
if(l==r) return dat[pos];
pushdown(pos);
int mid=(l+r)>>1;
if(x<=mid) return query(pos<<1,l,mid,x);
else return query(pos<<1|1,mid+1,r,x);
}
}
int main(){
freopen("darkteam.in","r",stdin);
freopen("darkteam.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&a[i].h),a[i].id=i;
for(int i=n+1;i<=n+m;++i){
scanf("%d",&k[i]);
if(k[i]==2) scanf("%d",&x[i]);
scanf("%d",&a[i].h);
a[i].id=i;
}
sort(a+1,a+1+n+m);
h[a[1].id]=1;
for(int i=2;i<=n+m;++i) h[a[i].id]=a[i].h>a[i-1].h?h[a[i-1].id]+1:h[a[i-1].id];
mx=h[a[n+m].id];
for(int i=1;i<=n;++i) if(h[i-1]<h[i]) TREE::modify(1,1,mx,h[i-1]+1,h[i],1);
for(int i=n+1;i<=n+m;++i){
if(k[i]==2){
int t=x[i];
if(h[t-1]<h[t]) TREE::modify(1,1,mx,h[t-1]+1,h[t],-1);
if(t!=n&&h[t]<h[t+1]) TREE::modify(1,1,mx,h[t]+1,h[t+1],-1);
h[t]=h[i];
if(h[t-1]<h[t]) TREE::modify(1,1,mx,h[t-1]+1,h[t],1);
if(t!=n&&h[t]<h[t+1]) TREE::modify(1,1,mx,h[t]+1,h[t+1],1);
}
else printf("%d\n",TREE::query(1,1,mx,h[i]));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具