题目大意:数轴上有n座楼,初始高度为0,每次可以改变某栋楼的高度,求每次改变高度之后从原点可以看到几栋楼
题解:记每栋楼楼顶与原点连线的斜率,那么一栋楼可见当且仅当前面所有楼的斜率都小于这栋楼
分块:块内维护特殊的lis,4 1 2 3 5 那么维护的序列就是4 5
块内暴力修改,查询的时候从下一块找到比这一块max大的即可
线段树做法:结点维护ans和mx,ans表示这个区间的答案,mx表示这个区间的最大斜率。
合并区间:对于节点x,ls的答案可以完全加入x的答案,接下来考虑rs
记ls最大值为
M
若rs最大值小于等于
若大于
M
,把rs分成左右区间处理
若rs左区间mx小于等于
若rs左区间mx大于
M
<script id="MathJax-Element-221" type="math/tex">M</script>,则递归处理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,1
int 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;
}