P4198 楼房重建 线段树 + 单调栈

传送门
题面有点小问题,个人感觉应该是存在一个点不相交即可。
改成存在的话,理解起来就比较简单了,就是维护每个点到 (0,0) 的斜率,从前往后做一遍单调递增栈得到的单调栈长度即为答案。不过显然需要数据结构来维护,可以考虑线段树。
修改操作的两个区间合并的时候,并不能直接合并,需要发现一些潜在的性质。
(1) 左区间的第一个点一定是要选的
(2) 左区间的最大值一定要选
知道这两点之后,那么答案就是 len( L ) + cal ( R , max_len( L ) ),cal是找右区间大于左区间最大值的单调栈长度。
在cal函数的时候,如果当前区间最大值都 <= x ,那么直接返回0即可。如果递归到叶子结点则根据情况返回 1 或 0。如果左区间的最大值 <= x ,显然左区间的都可以弹掉,递归右区间。否则的话返回 递归左区间 + len(u) - len(L) ,递归左区间比较容易想到,但是为什么不需要处理右区间呢?因为如果可以递归左区间的话,那么说明 左区间的最大值 > x,否则就被弹掉了 ,而我们两个区间的长度都已经是处理好了的,比如找个样例 4 5 6 1 2 8 ,len(u) = 4 ,len(L) = 3 ,我们在没有执行cal函数的时候,已经得到了相应长度,这里保证了两个区间选到的数中,左边选的数 < 右边选的数。那么假设 x = 5 吧,递归左区间返回1,选的这个数是6,右边选的数要保证大于6的话,就应该在 len(u) 中去掉 len(L) 即可。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=100010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,m;
struct Node
{
    int l,r;
    int len;
    double mx;
}tr[N<<2];

void pushup(int u)
{
    tr[u].mx=max(tr[L].mx,tr[R].mx);
}

int cal(int u,double x)
{
    if(tr[u].mx<=x) return 0;
    if(tr[u].l==tr[u].r) return tr[u].mx>x;
    if(tr[L].mx<=x) return cal(R,x);
    else return tr[u].len-tr[L].len+cal(L,x);
}

void build(int u,int l,int r)
{
    tr[u]={l,r};
    if(l==r) return;
    build(L,l,Mid),build(R,Mid+1,r);
}

void modify(int u,int l,int r,double c)
{
    if(tr[u].l==tr[u].r)
    {
        tr[u].mx=c; tr[u].len=1;
        return;
    }
    if(l<=Mid) modify(L,l,r,c);
    else modify(R,l,r,c);
    pushup(u);
    tr[u].len=tr[L].len+cal(R,tr[L].mx);
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    cin>>n>>m;
    build(1,1,n);
    while(m--)
    {
        int x,y; scanf("%d%d",&x,&y);
        double k=1.0*y/x;
        modify(1,x,x,k);
        printf("%d\n",tr[1].len);
    }





	return 0;
}
/*

*/









猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/106980235