【题解】Luogu P4198 楼房重建

原题传送门

根据斜率来建线段树,线段树维护区间最大斜率以及区间内能看见的楼房的数量(不考虑其他地方的原因,两个节点合并时再考虑)

细节见程序

#include <bits/stdc++.h>
#define db double 
#define N 100005
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline db Max(register db a,register db b)
{
    return a>b?a:b;
}
int n,m;
int ans[N<<3];
db maxx[N<<3];
inline int query(register int x,register int l,register int r,register db v)
{
    if(maxx[x]<=v)
        return 0;
    else if(l==r)
        return maxx[x]>v;
    else if(maxx[x<<1]<=v)
        return query(x<<1|1,(l+r>>1)+1,r,v);
    else
        return query(x<<1,l,l+r>>1,v)+ans[x]-ans[x<<1];
}
inline void update(register int x,register int l,register int r,register int pos,register db v)
{
    if(l==r)
    {
        ans[x]=1,maxx[x]=v;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid)
        update(x<<1,l,mid,pos,v);
    else
        update(x<<1|1,mid+1,r,pos,v);
    maxx[x]=Max(maxx[x<<1],maxx[x<<1|1]);
    ans[x]=ans[x<<1]+query(x<<1|1,mid+1,r,maxx[x<<1]);
}
int main()
{
    n=read(),m=read();
    while(m--)
    {
        int pos=read(),h=read();
        update(1,1,n,pos,(db)h/pos);
        write(ans[1]),puts("");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yzhang-rp-inf/p/10349148.html
今日推荐