问题:
小 A 的楼房外有一大片施工工地,工地上有 N 栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。
为了简化问题,我们考虑这些事件发生在一个二维平面上。小 AA 在平面上 (0,0) 点的位置,第 ii 栋楼房可以用一条连接 (i,0) 和 (i,Hi?) 的线段表示,其中 Hi? 为第 i栋楼房的高度。 如果这栋楼房上存在一个高度大于 0 的点与 (0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。
施工队的建造总共进行了 M 天。初始时,所有楼房都还没有开始建造,它们的高度均为 0 。 在第 i 天,建筑队将会将横坐标为 Xi? 的房屋的高度变为 Yi? (高度可以比原来大—修建,也可以比原来小—拆除,甚至可以保持不变—建筑队这天什么事也没做)。 请你帮小 A 数数每天在建筑队完工之后,他能看到多少栋楼房?
解:
注意一些点
如果是要求修改的 绝大部分是数据结构
不要再往逆序对上想了啊!
$1$ 线段树
分治 分而治之
cnt代表当前区间内可行的总数
code:
// #include<stdio.h> #include<bits/stdc++.h> using namespace std; #define maxnn 700000 int n,m; struct node { int x,y,cnt; double val; }tree[maxnn]; void build(int p,int a,int b) { tree[p].x=a; tree[p].y=b; if(a<b) { int mid=(a+b)/2; build(p<<1,a,mid); build(p<<1|1,mid+1,b); } } int query(int p,double lim) { if(tree[p].val<=lim) return 0; if(tree[p].x==tree[p].y) return (tree[p].val>lim); int mid=(tree[p].x+tree[p].y)/2; if(tree[p<<1].val<=lim) return query(p<<1|1,lim); else return tree[p].cnt-tree[p<<1].cnt+query(p<<1,lim); 右边可行的 + 左边门槛大于lim 的 } void modify(int p,int yY,double d) { if(tree[p].x==tree[p].y) {tree[p].val=d;tree[p].cnt=1;} else { int mid=(tree[p].x+tree[p].y)/2; if(yY<=mid) modify(p<<1,yY,d); else if(yY>mid) modify(p<<1|1,yY,d); tree[p].cnt=tree[p<<1].cnt+query(p<<1|1,tree[p<<1].val); 左边没有门槛的 + 右边门槛大于左边最大值的 tree[p].val=max(tree[p<<1].val,tree[p<<1|1].val); } } int main() { cin>>n>>m; int x,y; build(1,1,n); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); modify(1,x,double(y)/x); 这里卡好久... printf("%d\n",tree[1].cnt); } }
$2$ 分块
巨佬代码链接:
https://www.luogu.org/blog/HuangYuhan-Yuzhe/nkoj-0817-zhuan-xiang-lian-xi
原文地址:https://www.cnblogs.com/OIEREDSION/p/11370902.html
时间: 2024-10-01 05:10:09