【洛谷】P4198 楼房重建

时间:2023-03-09 00:03:51
【洛谷】P4198 楼房重建

题解

我们转而维护每个点的斜率,显然一个楼房能被看见它就是一个前缀最大值,斜率比较为了节约精度可以用向量替代

我们每个区间维护被看到的楼房的个数,和楼房的最大值,叶子节点在有楼房时,值为1

那么考虑合并两个区间,左节点的所有能被看到的楼房还是能被看到,右边节点能看到的楼房的斜率需要大于左边节点所需要的斜率最大值

为了找到这些我们去右节点的左右区间去找

如果这个值\(P\)大于等于区间左边的最大值,那么这个值要在右边找

如果小于的话,加上右边的大小,即\(tr[u].cnt - tr[u << 1].cnt\),然后递归到左边处理

复杂度\(O(n \log^2 n)\)

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
struct Point {
int64 x,y;
Point(int64 _x = 0,int64 _y = 0) {
x = _x;y = _y;
}
friend Point operator + (const Point &a,const Point &b) {
return Point(a.x + b.x,a.y + b.y);
}
friend Point operator - (const Point &a,const Point &b) {
return Point(a.x - b.x,a.y - b.y);
}
friend int64 operator * (const Point &a,const Point &b) {
return a.x * b.y - a.y * b.x;
}
friend bool operator < (const Point &a,const Point &b) {
return a * b > 0;
}
friend bool operator > (const Point &a,const Point &b) {
return a * b < 0;
}
friend bool operator == (const Point &a,const Point &b) {
return a * b == 0;
}
friend bool operator >= (const Point &a,const Point &b) {
return a > b || a == b;
}
friend bool operator <= (const Point &a,const Point &b) {
return a < b || a == b;
}
};
struct node {
int L,R,cnt;Point P;
}tr[MAXN * 4];
int N,M; void build(int u,int l,int r) {
tr[u].L = l;tr[u].R = r;tr[u].cnt = 0;
tr[u].P = Point(r,0);
if(l == r) return;
int mid = (l + r) >> 1;
build(u << 1,l,mid);
build(u << 1 | 1,mid + 1,r);
}
int Calc(int u,Point P) {
if(tr[u].L == tr[u].R) return tr[u].P > P;
if(P >= tr[u << 1].P) {
return Calc(u << 1 | 1,P);
}
else {
return Calc(u << 1,P) + tr[u].cnt - tr[u << 1].cnt;
}
}
void Change(int u,int pos,int y) {
if(tr[u].L == tr[u].R) {
tr[u].P = Point(pos,y);
if(!y) tr[u].cnt = 0;
else tr[u].cnt = 1;
return;
}
int mid = (tr[u].L + tr[u].R) >> 1;
if(pos <= mid) Change(u << 1,pos,y);
else Change(u << 1 | 1,pos,y);
tr[u].P = max(tr[u << 1].P,tr[u << 1 | 1].P);
tr[u].cnt = tr[u << 1].cnt + Calc(u << 1 | 1,tr[u << 1].P);
}
void Solve() {
read(N);read(M);
build(1,1,N);
int x,y;
for(int i = 1 ; i <= M ; ++i) {
read(x);read(y);
Change(1,x,y);
out(tr[1].cnt);enter;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}