洛谷 P4198 楼房重建(线段树维护单调序列)

传送门

解题思路

动态维护区间里面单调递增斜率的长度

需要维护两个信息:上述长度,和区间最大值(合并时需要)

难点在于两个子区间的合并。

左区间的楼房一定都能看见(没有遮挡),所以要在右区间二分,找到左面最大值 lmax 在右区间的位置,然后进行合并。

复杂度两个log。

AC代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
inline 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*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=100005;
double a[maxn],d[maxn*4];
int len[maxn*4],n,m;
int getans(int id,int l,int r,double x){
	if(l==r) return a[l]>x;
	if(d[id]<=x) return 0;
	int mid=(l+r)/2;
	if(d[id*2]>x) return len[id]-len[id*2]+getans(id*2,l,mid,x);
	else return getans(id*2+1,mid+1,r,x);
}
void pushup(int id,int l,int r){
	d[id]=max(d[id*2],d[id*2+1]);
	int mid=(l+r)/2;
	len[id]=len[id*2]+getans(id*2+1,mid+1,r,d[id*2]);
}
void add(int id,int l,int r,int x,double v){
	if(l==r){
		d[id]=v;
		len[id]=1;
		return;
	}
	int mid=(l+r)/2;
	if(x<=mid) add(id*2,l,mid,x,v);
	else add(id*2+1,mid+1,r,x,v);
	pushup(id,l,r);
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;i++){	
		int x=read(),y=read();
		a[x]=1.0*y/x;
		add(1,1,n,x,a[x]);
		printf("%d\n",len[1]);
	}
    return 0;
}
posted @ 2024-02-25 11:36  尹昱钦  阅读(25)  评论(0编辑  收藏  举报