Luogu P4198 楼房重建

题目
考虑每个楼房的顶楼到\((0,0)\)的斜率\(k\),那么能看到的楼房就是满足前面的\(k\)都比它自己的\(k\)小的。
考虑线段树,每个节点维护当前区间内的最大的\(k\)(记为\(mx\)),和把当前这段区间单独拿出来考虑的答案(记为\(val\))。
我们要支持的就是单点修改和全局查询。全局查询就是\(1\)这个节点的答案。
单点修改我们可以直接到底层然后往上pushup回来,维护\(mx\)非常容易,但是维护\(val\)并不好做。
假如现在有一个线段树节点\(p\),我们要合并其左右儿子\(ls,rs\)所代表的的区间然后求答案。
首先我们知道\(val_{ls}\)会全部计算进来,但是\(rs\)会受到\(mx_{ls}\)的影响导致答案变小。
我们考虑在线段树上从\(rs\)往下递归计算这个答案。
假设当前递归到的节点为\(p'\),左右儿子分别为\(ls',rs'\)
如果\(mx_{p'}\le mx_{ls}\)小,那么这一段区间的答案都是\(0\)
如果\(p'\)所代表的区间的第一个\(k\)\(mx_{ls}\)大,那么这一段区间不受影响,答案不变。
否则我们再看当前\(ls',rs'\)所代表的区间。
如果\(mx_{ls'}\le mx_{ls}\),那么我们可以直接往\(rs'\)递归,因为此时\(ls'\)所代表的区间不会有任何影响。
否则我们递归计算\(ls'\)的答案,而\(rs'\)的答案就是\(val_{p'}-val_{ls'}\)。因为\(mx_{ls'}>mx_{ls}\),所以\(mx_{ls}\)相当于没有影响,\(rs'\)所代表区间的答案就是和\(ls'\)放在一起的贡献的答案。
这样每次修改我们的复杂度都为\(O(\log^2 n)\),所以总复杂度为\(O(n\log^2 n)\)

#include<cstdio>
#include<cctype>
#include<iostream>
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
#define db double
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[11],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    void write(int x){int top=0;while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');}
}
using namespace IO;
const int N=100007;
int n,m,val[N<<2];db a[N],mx[N<<2];
void pushup(int p){mx[p]=max(mx[ls],mx[rs]);}
int query(int p,int l,int r,db k)
{
    if(mx[p]<=k) return 0;
    if(a[l]>k) return val[p];
    return mx[ls]<=k? query(rs,mid+1,r,k):query(ls,l,mid,k)+val[p]-val[ls];
}
void update(int p,int l,int r,int x,db k)
{
    if(l==r) return (void)(val[p]=1,mx[p]=k);
    (x<=mid? update(ls,l,mid,x,k):update(rs,mid+1,r,x,k)),pushup(p),val[p]=val[ls]+query(rs,mid+1,r,mx[ls]);
}
int main()
{
    n=read(),m=read();
    for(int x,y;m;--m) x=read(),y=read(),a[x]=(db)y/x,update(1,1,n,x,a[x]),write(val[1]);
    return Flush(),0;
}
posted @ 2019-11-29 19:36  Shiina_Mashiro  阅读(144)  评论(0编辑  收藏  举报