AKVARIJ(ZJNU 1806)
题目大意
你有一个宽度为的电脑屏幕,左端点的坐标为,右端点为,你的屏保是一个水族馆,对于每个点都可以自定义一个高度,代表沙丘的高度,水族馆的水的高度也能自定义,范围在内。现在你有每一个点的沙丘的初始高度,每次你有两种操作:表示询问当水的高度为时水的面积为多少;表示把坐标为的点的沙丘的高度调整为。对于每一次操作一,输出要求的答案。
思路一
由于是对高度经行询问,我们考虑把每一层水的面积当成叶子节点建一棵线段树,这样每一次修改,我们都可以把他转化为对区间加上一个等差数列,这样问题就很好的得到了解决。
代码一
#include<bits/stdc++.h> using namespace std; int n,m; double tree[1005<<2],laz1[1005<<2],laz2[1005<<2]; void pushdown(int p,int l,int r) { int mid=(l+r)>>1; double x=laz1[p],y=laz2[p]; laz1[p<<1]+=x; laz2[p<<1]+=y; laz1[p<<1|1]+=x+y*(mid-l+1); laz2[p<<1|1]+=y; tree[p<<1]+=(x+x+(mid-l)*y)*(mid-l+1)/2; tree[p<<1|1]+=(x+y*(mid-l+1)+x+y*(mid-l+1)+(r-mid-1)*y)*(r-mid)/2; laz1[p]=laz2[p]=0; } void build(int p,int l,int r) { laz1[p]=laz2[p]=0; if(l==r) {tree[p]=n-1; else { int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); tree[p]=tree[p<<1]+tree[p<<1|1]; } } void update(int p,int l,int r,double v,double d,int x,int y) { if(x<=l&&r<=y) { double vv=v+(l-x)*d; laz1[p]+=vv; laz2[p]+=d; tree[p]+=(vv+vv+d*(r-l))*(r-l+1)/2; } else { int mid=(l+r)>>1; pushdown(p,l,r); if(x<=mid)update(p<<1,l,mid,v,d,x,y); if(mid<y)update(p<<1|1,mid+1,r,v,d,x,y); tree[p]=tree[p<<1]+tree[p<<1|1]; } } double query(int p,int l,int r,int x,int y) { if(x<=l&&r<=y)return tree[p]; else { pushdown(p,l,r); int mid=(l+r)>>1; double ans=0; if(x<=mid)ans+=query(p<<1,l,mid,x,y); if(mid<y)ans+=query(p<<1|1,mid+1,r,x,y); tree[p]=tree[p<<1]+tree[p<<1|1]; return ans; } } int h[100005]; int main() { scanf("%d%d",&n,&m); for(int i=0;i<n;i++)scanf("%d",&h[i]); build(1,1,1000); for(int i=0;i<n-1;i++) { int minn=min(h[i],h[i+1]); int maxx=max(h[i],h[i+1]); if(minn>=1)update(1,1,1000,-1,0,1,minn); if(maxx>minn)update(1,1,1000,-(1.0-1.0/(maxx-minn)/2),1.0/(maxx-minn),minn+1,maxx); } while(m--) { char op[10]; scanf("%s",op+1); if(op[1]=='Q') { int H; scanf("%d",&H); if(H==0)printf("0.000\n"); else printf("%.3f\n",query(1,1,1000,1,H)); } else { int id,H; scanf("%d%d",&id,&H); if(id>0) { if(h[id]>h[id-1]) { update(1,1,1000,1.0-1.0/(h[id]-h[id-1])/2,-1.0/(h[id]-h[id-1]),h[id-1]+1,h[id]); } else if(h[id]<h[id-1]) { update(1,1,1000,-1.0/(h[id-1]-h[id])/2,-1.0/(h[id-1]-h[id]),h[id]+1,h[id-1]); } if(H>h[id-1]) { update(1,1,1000,-(1.0-1.0/(H-h[id-1])/2),1.0/(H-h[id-1]),h[id-1]+1,H); } else if(H<h[id-1]) { update(1,1,1000,1.0/(h[id-1]-H)/2,1.0/(h[id-1]-H),H+1,h[id-1]); } } if(id<n-1) { if(h[id]>h[id+1]) { update(1,1,1000,1.0-1.0/(h[id]-h[id+1])/2,-1.0/(h[id]-h[id+1]),h[id+1]+1,h[id]); } else if(h[id]<h[id+1]) { update(1,1,1000,-1.0/(h[id+1]-h[id])/2,-1.0/(h[id+1]-h[id]),h[id]+1,h[id+1]); } if(H>h[id+1]) { update(1,1,1000,-(1.0-1.0/(H-h[id+1])/2),1.0/(H-h[id+1]),h[id+1]+1,H); } else if(H<h[id+1]) { update(1,1,1000,1.0/(h[id+1]-H)/2,1.0/(h[id+1]-H),H+1,h[id+1]); } } h[id]=H; } } return 0; }
思路二
我们还能发现,如果把深度为的水的面积为叶子节点建一棵线段树,那么对于一块方形的沙丘,相当于减去,而三角形的沙丘,可以看成减去,于是我们就可以直接维护这三个系数,就可以避免写繁琐的线段树维护等差数列,代码就再说叭~
__EOF__

本文作者:Jerry-Black
本文链接:https://www.cnblogs.com/Jerry-Black/p/16455950.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
本文链接:https://www.cnblogs.com/Jerry-Black/p/16455950.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)