2957: 楼房重建

来源:互联网 发布:java调用其他类的函数 编辑:程序博客网 时间:2024/06/08 15:20

题目链接

题目大意:数轴上有n座楼,初始高度为0,每次可以改变某栋楼的高度,求每次改变高度之后从原点可以看到几栋楼

题解:记每栋楼楼顶与原点连线的斜率,那么一栋楼可见当且仅当前面所有楼的斜率都小于这栋楼
分块:块内维护特殊的lis,4 1 2 3 5 那么维护的序列就是4 5
块内暴力修改,查询的时候从下一块找到比这一块max大的即可

线段树做法:结点维护ans和mx,ans表示这个区间的答案,mx表示这个区间的最大斜率。
合并区间:对于节点x,ls的答案可以完全加入x的答案,接下来考虑rs
记ls最大值为M
若rs最大值小于等于M,则rs没有贡献
若大于M,把rs分成左右区间处理
若rs左区间mx小于等于M,则递归处理rs右区间
若rs左区间mx大于M,则递归处理rs左区间,同时加上rs右区间的答案
右子区间的答案要用右区间答案-左子区间答案,不能直接调用右子区间本身答案,因为其本身答案没有考虑左子区间的约束。

我的收获:强强强

分块

#include <cstdio>#include <cstring>#include <iostream>#include <cmath>#include <algorithm>using namespace std;#define M 100100  #define eps 1e-10  int n,m,blo,num,pos[M];  double a[M];  struct Block{    int tot,l,r;    double ele[1010];    void rebuild()//本来TLE了,换成结构体函数就过了……     {        double tmp=0;tot=0;        for(int i=l;i<=r;i++)            if(a[i]>tmp+eps)                tmp=a[i],ele[++tot]=a[i];    }    int cal(double &x)    {        int ret=(tot+1)-(upper_bound(ele+1,ele+tot+1,x+eps)-ele);        if(ret) x=ele[tot];        return ret;    }}b[120];void work(){    int x,y;    for(int i=1;i<=m;i++)    {        scanf("%d%d",&x,&y);        a[x]=(double)y/x;        b[pos[x]].rebuild();        int ans=0;double tmp=0;        for(int j=1;j<=num;j++)              ans+=b[j].cal(tmp);        printf("%d\n",ans);    }}void init(){    cin>>n>>m;    blo=sqrt(n*log(n)/log(2)/2);num=n/blo+1;    for(int i=1;i<=n;i++) pos[i]=(i-1)/blo+1;    for(int i=1;i<=num;i++)        b[i].l=(i-1)*blo+1,b[i].r=min(i*blo,n);}int main(){    init();    work();    return 0;}

线段树

#include <cstdio>#include <cstring>#include <iostream>#include <cmath>#include <algorithm>using namespace std;#define M 100005#define ls x<<1#define rs x<<1|1#define lson l,m,x<<1#define rson m+1,r,x<<1|1#define root 1,n,1int n,m,ans[M<<2],tl[M<<2],tr[M<<2];double mx[M<<2];int cal(double k,int x){    int l=tl[x],r=tr[x];    if(l==r) return mx[x]>k;//特判叶子结点    if(mx[ls]<=k) return cal(k,rs);    return ans[x]-ans[ls]+cal(k,ls);}void pushup(int x){mx[x]=max(mx[ls],mx[rs]);ans[x]=ans[ls]+cal(mx[ls],rs);}void build(int l,int r,int x){    if(l==r) return ;    int m=(l+r)>>1;    tl[x]=l,tr[x]=r;    build(lson);build(rson);}void updata(int p,double k,int x){    int l=tl[x],r=tr[x];    if(l==r){ans[x]=1;mx[x]=k;return ;}    int m=(l+r)>>1;    if(p<=m) updata(p,k,ls);    else updata(p,k,rs);    pushup(x);}void work(){    int x,y;    for(int i=1;i<=m;i++)    {        scanf("%d%d",&x,&y);        updata(x,(double)y/x,1);        printf("%d\n",ans[1]);     }}void init(){    cin>>n>>m;    build(root);}int main(){    init();    work();    return 0;}
0 0
原创粉丝点击