Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 3042 Solved: 1414
[Submit][Status][Discuss]
Description
小A的楼房外有一大片施工工地,工地上有N栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。
为了简化问题,我们考虑这些事件发生在一个二维平面上。小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度。如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。
施工队的建造总共进行了M天。初始时,所有楼房都还没有开始建造,它们的高度均为0。在第i天,建筑队将会将横坐标为Xi的房屋的高度变为Yi(高度可以比原来大---修建,也可以比原来小---拆除,甚至可以保持不变---建筑队这天什么事也没做)。请你帮小A数数每天在建筑队完工之后,他能看到多少栋楼房?
Input
第一行两个正整数N,M
接下来M行,每行两个正整数Xi,Yi
Output
M行,第i行一个整数表示第i天过后小A能看到的楼房有多少栋
Sample Input
3 4
2 4
3 6
1 1000000000
1 1
Sample Output
1
1
1
2
数据约定
对于所有的数据1<=Xi<=N,1<=Yi<=10^9
N,M<=100000
HINT
Source
中国国家队清华集训 2012-2013 第一天
题解
万能的线段树啊,请赐予我SDOI2018爆零的力量吧。。。。
每个节点维护仅考虑当前区间的楼房时,区间内的可见数目和区间内最大斜率
考虑如何合并两段区间,左区间可以直接继承过来,右区间则需要讨论一下,设左区间最大斜率为k
若k大于等于右区间的最大斜率,则右区间无贡献
考虑右区间的左右儿子在斜率k的限制下的贡献
若k大于等于左儿子的斜率,那么左儿子没有贡献,递归计算右儿子
若k小于左儿子的斜率,说明右儿子受到左儿子约束时的贡献就是右儿子的贡献,因此右儿子的贡献就是区间贡献减去左儿子贡献(注意:此处不能直接用右儿子贡献,因为根据定义,右儿子贡献是仅考虑右儿子,不考虑左儿子对其约束的,因此需要用右区间贡献减去左儿子贡献才是有左儿子限制的右儿子贡献),左儿子的贡献递归求解(因为受到了斜率k的限制)
脑子有点晕(困),写的是时候build没调用(居然过样例了真神奇),调用之后发现过不了样例了,发现build脑抽般的写错一个地方
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
inline long long max(long long a, long long b){return a > b ? a : b;}
inline double max(double a, double b){return a - b > 0 ? a : b;}
inline long long min(long long a, long long b){return a < b ? a : b;}
inline void swap(long long &x, long long &y){long long tmp = x;x = y;y = tmp;}
inline void read(long long &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const long long INF = 0x3f3f3f3f;
const long long MAXN = 100000 + 10;
struct Node
{
double ma;
long long sum, l, r;
Node(){}
}node[MAXN << 2];
long long calc(long long o, double k)
{
if(node[o].ma <= k) return 0;
if(node[o].l == node[o].r) return node[o].ma > k;
if(node[o << 1].ma > k)
return calc(o << 1, k) + node[o].sum - node[o << 1].sum;
else
return calc(o << 1 | 1, k);
}
void pushup(long long o)
{
node[o].ma = max(node[o << 1].ma, node[o << 1 | 1].ma);
node[o].sum = node[o << 1].sum + calc(o << 1 | 1, node[o << 1].ma);
}
long long n, q;
void build(long long o = 1, long long l = 1, long long r = n)
{
node[o].l = l, node[o].r = r;
if(node[o].l == node[o].r) return;
long long mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
}
void modify(long long p, long long k, long long o = 1)
{
if(node[o].l == node[o].r)
{
node[o].ma = (double)k / p;
node[o].sum = 1;
return;
}
long long mid = (node[o].l + node[o].r) >> 1;
if(mid >= p) modify(p, k, o << 1);
else modify(p, k, o << 1 | 1);
pushup(o);
return;
}
int main()
{
read(n), read(q);
build();
for(long long i = 1;i <= q;++ i)
{
long long tmp1,tmp2;
read(tmp1), read(tmp2);
modify(tmp1, tmp2);
printf("%lld\n", node[1].sum);
}
return 0;
}