题解:楼房重建
题意分析
设第 \(i\) 栋楼房的高度为 \(h_i\)。
那么 \((i,h_i)\) 能被看见当且仅当:
记 \(k_i=\dfrac{h_i}i\),则题意即动态维护一个序列,\(k_1\) 必须选,且选中的 \(k_i\) 均为前缀严格最大值。
普通静态方法都不行,不能接受。考虑充分利用已有信息,那么容易想到线段树合并区间。
对于节点 \(p\),维护 \(\textit{len}_p\) 表示 \([l_p,r_p]\) 的最长长度。
考虑 \([l,\textit{mid}],[\textit{mid}+1,r]\) 合并到 \([l,r]\)。
显然 \([l,\textit{mid}]\) 部分的答案一定不变,重要的是如何求出 \([\textit{mid}+1,r]\) 的答案。右子区间 \([\textit{mid}+1,r]\) 内最终选中的所有 \(k_i\) 必须都要大于左子区间 \([l,\textit{mid}]\) 的最大值,记为 \(s=\max[l,\textit{mid}]\)。
对于 \([\textit{mid}+1,r]\) 内,设其左子区间 \([l',\textit{mid}']\)、右子区间 \([\textit{mid}'+1,r']\)。
-
若 \(\max[l',\textit{mid}']\leq s\),则 \([l',\textit{mid}']\) 一定不在答案内,答案在 \([\textit{mid}'+1,r]\) 中。
-
若 \(\max[l',\textit{mid}']>s\),则 \([l',\textit{mid}']\) 一定在答案内,需要先计算这一部分。
考虑 \([\textit{mid}'+1,r']\) 的答案是什么,和上面是类似的,这一部分要大于 \(\max[l',\textit{mid}'+1]\)。
因此直接得到这一部分的答案为 \(\textit{len}_{[l',r']}-\textit{len}_{[l',\textit{mid}']}\)。
由于线段树的性质,处理 \([l,r]\) 时,这些信息都已知。
这么看下来,这就是一个递归求解的过程,单次复杂度 \(\mathcal O(\log n)\)。
形式化地,设 \(\operatorname{find}(p,s)\) 表示 \([l_p,r_p]\) 内大于 \(s\) 的答案(不一定从 \(l_p\) 开始),\(\textit{lChild}_p,\textit{rChild}_p\) 分别为左右子节点,\(\textit{max}_p\) 表示 \([l_p,r_p]\) 内的最大值。
则:
总时间复杂度 \(\mathcal O\left(m\log^2n\right)\)。
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=1e5;
struct k{
int x,y;
k(){
x=1,y=-2147483647;
}
k(int x2,int y2){
x=x2,y=y2;
}
};
bool operator <(k a,k b){
return 1ll*a.y*b.x < 1ll*b.y*a.x;
}
bool operator >(k a,k b){
return 1ll*a.y*b.x > 1ll*b.y*a.x;
}
bool operator ==(k a,k b){
return 1ll*a.y*b.x == 1ll*b.y*a.x;
}
bool operator <=(k a,k b){
return !(a>b);
}
struct segTree{
struct node{
int l,r,len;
k max;
}t[N<<2|1];
int find(int p,k s){
if(t[p].max<=s){
return 0;
}else if(t[p].l==t[p].r){
return 1;
}else if(t[p<<1].max<=s){
return find(p<<1|1,s);
}else{
return find(p<<1,s)+t[p].len-t[p<<1].len;
}
}
void up(int p){
t[p].max=max(t[p<<1].max,t[p<<1|1].max);
t[p].len=t[p<<1].len+find(p<<1|1,t[p<<1].max);
}
void build(int p,int l,int r){
t[p]={l,r};
if(l==r){
return;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
up(p);
}
void set(int p,int x,int y){
if(t[p].l==t[p].r){
t[p].max={x,y};
t[p].len=1;
return;
}
if(x<=t[p<<1].r){
set(p<<1,x,y);
}
if(t[p<<1|1].l<=x){
set(p<<1|1,x,y);
}
up(p);
}
int query(){
return t[1].len;
}
}t;
main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,m;
cin>>n>>m;
t.build(1,1,n);
while(m--){
int x,y;
cin>>x>>y;
t.set(1,x,y);
cout<<t.query()<<'\n';
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号