P4198 楼房重建 (线段树)
求从
对于带修改的题目,我们需要快速维护,就需要用到数据结构。这时候通过直觉可以想到,问题是可以分为子问题然后合并得到的,所以我们考虑线段树。
观察到能被看到的楼房,从左到右斜率递增,即我们需要维护斜率递增的序列。
考虑子区间需要维护的信息,发现该区间对其他区间的影响只跟其斜率最大值有关,所以一个是维护区间斜率最大值
怎么合并?记
如果
否则
这部分思考变成代码也很简单,由于每次只会递归一个区间,复杂度单次是
所以是 update 的同时套一个
#include <bits/stdc++.h>
using namespace std;
int read(){
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c - '0');
c = getchar();
}
return x * f;
}
int n, m;
struct node{
double max;
int cnt;
}t[100010 << 2];
void pushup(int u){
t[u].max = max(t[u << 1].max, t[u << 1 | 1].max);
}
int calc(int u, int l, int r, double pre){
if(l == r) return t[u].max > pre;
int mid = (l + r) >> 1;
if(t[u << 1].max <= pre) return calc(u << 1 | 1, mid + 1, r, pre);
return calc(u << 1, l, mid, pre) + (t[u].cnt - t[u << 1].cnt);
}
void update(int u, int l, int r, int x, int y){
if(l == r){
t[u].cnt = 1;
t[u].max = (double)y / x;
return;
}
int mid = (l + r) >> 1;
if(x <= mid) update(u << 1, l, mid, x, y);
else update(u << 1 | 1, mid + 1, r, x, y);
pushup(u);
t[u].cnt = t[u << 1].cnt + calc(u << 1 | 1, mid + 1, r, t[u << 1].max);
}
int main(){
n = read(), m = read();
for(int i = 1; i <= m; i++){
int x = read(), y = read();
update(1, 1, n, x, y);
printf("%d\n", t[1].cnt);
}
return 0;
}
标签:
线段树
Buy me a cup of coffee ☕.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具