P4198 楼房重建
看到带修改,显然会想到数据结构来维护,再看到再平面区间加减和区间查询,显然又会想到线段树。
那线段树的每一个节点要维护什么值呢?
看到题面自然会想到斜率
所以问题就可以转化成求一个最长递增的斜率
既然是单调递增,那么我们线段树的每一个节点可以维护这个节点所对应的区间的最大值,与从这段区间开头可以看到的区间内的所有楼房
那么我们要怎么查询呢?
答案显然是第一个节点(根节点)的答案
所以我们现在的主要问题就是怎么修改
对于每一个叶子节点,从这段区间头可以看到的楼房数量一定为11,区间斜率最大值一定为该点的斜率
那么合并呢?
显然合并区间的所有楼房一定可以看到左边的区间第一个位置看到的所有楼房
对于右边的来说,我们采用一个递归的思想,就相当于在右区间第一个位置放了一个 [左边最高的斜率] 高度的楼房,所以找右边高于左边最高楼房的个数就是右边的数量了
如何求右边,也采用递归的思想,先看左区间能不能满足,然后看右区间
所以复杂度是 \(O(nlog^2n)\)
其实就可以这样思考,我们利用线段树来实现一个分治的想法,把每个大问题来当做两个子问题来看待
所以我们在递归左区间的时候答案就是\(query(x<<1,l,mid,max_x)+c[x]-c[x<<1]\)
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int N,M,c[maxn<<2]; double d[maxn<<2]; struct IO{ static const int S=1<<21; char buf[S],*p1,*p2;int st[105],Top; ~IO(){clear();} inline void clear(){fwrite(buf,1,Top,stdout);Top=0;} inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;} inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='r');return *this;} template<typename T>inline IO&operator >> (T&x){ x=0;bool f=0;char ch=gc(); while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();} while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc(); f?x=-x:0;return *this; } inline IO&operator << (const char c){pc(c);return *this;} template<typename T>inline IO&operator << (T x){ if(x<0) pc('-'),x=-x; do{st[++st[0]]=x%10,x/=10;}while(x); while(st[0]) pc('0'+st[st[0]--]); return *this; } }fin,fout; int read(){ int ret=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar(); return ret*f; } int query(int x,int l,int r,double max_x){ if(d[x]<max_x)return 0; if(l==r)return d[x]>max_x; int mid=(r-l>>1)+l; if(d[x<<1]>max_x)return query(x<<1,l,mid,max_x)+c[x]-c[x<<1]; else return query(x<<1|1,mid+1,r,max_x); } void change(int x,int l,int r,int pos,double val){ if(l==pos&&r==pos){c[x]=1;d[x]=val;return ;} int mid=(r-l>>1)+l; if(pos<=mid)change(x<<1,l,mid,pos,val); else change(x<<1|1,mid+1,r,pos,val); d[x]=max(d[x<<1],d[x<<1|1]); c[x]=c[x<<1]+query(x<<1|1,mid+1,r,d[x<<1]); } int main(){ fin>>N>>M; for(int i=1;i<=M;i++){ int X,Y;fin>>X>>Y; change(1,1,N,X,(double)Y/X); fout<<c[1]<<'\n'; } return 0; }