zoukankan      html  css  js  c++  java
  • 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(nlog^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('
    ');}
    }
    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;
    }
    
  • 相关阅读:
    CF704D Captain America 上下界网络流
    CF241E Flights 差分约束
    CF1063F String Journey DP、SAM、线段树
    AGC028E High Elements 贪心、DP、线段树
    Solution -「CF 623E」Transforming Sequence
    Solution -「十二省联考2019」春节十二响
    最大团-最小度不等式
    「Lagrange 插值」学习笔记
    Solution -「NOI.AC 省选膜你赛」union
    Solution -「NOI.AC 省选膜你赛」T2
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11959869.html
Copyright © 2011-2022 走看看