【题解】洛谷P4198 楼房重建
因为有个bool调了一个小时,汤碗里。
显然能看到是斜率的问题,后面的斜率要严格大于前面的斜率才能够看见,所以这就是最大严格前缀长度问题。
有修改考虑线段树维护,信息合并时并不能直接合并,左部分可以直接合并,但右部分不能超过左部分的斜率最大值,所以我们用函数递归右区间判断,如果当前部分左区间的斜率最大值大于 \(K\),那右边全部合法,左边部分合法,函数调用左边,否则只有右边部分合法,函数递归调用右边。
真的要注意维护斜率,线段树上要维护斜率最大值所在的下标,判断斜率大小时返回 bool,我因此调了 \(1\) 个小时。
#include <bits/stdc++.h> #define ll long long #define int ll #define ls p<<1 #define rs p<<1|1 #define re register #define pb push_back #define pir pair<int,int> #define f(a,x,i) for(int i=a;i<=x;i++) #define fr(a,x,i) for(int i=a;i>=x;i--) #define lb(x) x&(-x); const int N=1<<18|7; const int mod=1e9+7; using namespace std; int n,m; int mx[N],H[N]; int cnt[N]; bool gt(int p1,int p2){ if(!p2) return H[p1]; return (ll)H[p1]*p2>(ll)H[p2]*p1; } int fs(int p,int k,int l,int r){ if(l==r) return gt(l,k); int mid=(l+r)>>1; if(gt(mx[ls],k)){ return fs(ls,k,l,mid)+cnt[p]-cnt[ls]; } else{ return 0+fs(rs,k,mid+1,r); } } void change(int p,int l,int r,int pos){ if(l==r) return; int mid=(l+r)>>1; if(pos<=mid) change(ls,l,mid,pos); else change(rs,mid+1,r,pos); mx[p]=gt(mx[rs],mx[ls])?mx[rs]:mx[ls]; cnt[p]=cnt[ls]+fs(rs,mx[ls],mid+1,r); } void build(int p,int l,int r){ mx[p]=l,cnt[p]=1; if(l==r) return; int mid=(l+r)>>1; build(ls,l,mid),build(rs,mid+1,r); } signed main(){ // freopen("xp1.in","r",stdin); ios::sync_with_stdio(0); cin.tie(nullptr); cin>>n>>m; build(1,1,n); while(m--){ int pos,x; cin>>pos>>x; H[pos]=x; change(1,1,n,pos); cout<<fs(1,0,1,n)<<"\n"; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具