BZOJ2957: 楼房重建

n<=100000栋楼房,第i栋在位置i,一开始全没建成高度0,m<=1e5个操作,每次操作把一栋楼x的高度修改为y,并问这次修改后从0位置往右边看能看到多少栋楼。他能看到一栋楼,必须这栋楼有高度,并且设楼高度Hi,那么(0,0)到(i,Hi)这条线段上没有其他的楼。1<=y<=1e9

说半天就是维护个斜率啦。。单点修改容易,不过这个信息有点难维护。。

可以用一个分治方法维护,现在是要求:从第一个有高度的楼房开始,斜率递增的最长序列有多长。把这个区间分成左右区间:

假如左右区间的要求的东西(即从该区间的第一个有高度的楼房开始的最长递增序列有多长)已知,那么在合并时,左区间的答案是可以直接算的,右区间收到左区间最大值的限制。也就是说,现在需要在右区间找:从该区间第一个大于左区间最大值的楼房开始的最长递增序列有多长。注意这里的递增都是在说斜率。

在右区间里面,关注一下左右子区间的信息和左区间最大值的关系,如果左子区间的最大值比左区间最大值小,那么接下来的在右子区间找大于左区间最大值的最长递增序列即可;反之,如果左子区间的最大值比左区间的大,那么右子区间在右区间里面表现出来的答案是不会变的,也就是:右区间的自己的以第一个有高度的楼房为起点的最长序列长度,减去左子区间的以……,剩下的部分就是右子区间收到左子区间最大值限制,以第一个大于左子区间最大值的楼房开始的最长序列,注意到这里说的还是“反之”的内容,这右子区间已知,那剩下的就是左子区间里面找大于左区间最大值的最长递增序列长度。

左右区间的操作?交给线段树或平衡树

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 //#include<assert.h>
 5 #include<math.h>
 6 #include<algorithm>
 7 //#include<iostream>
 8 using namespace std;
 9 
10 int n,m;
11 #define maxn 200011
12 const double eps=1e-12;
13 struct SMT
14 {
15     struct Node
16     {
17         double Max;int ans;
18         int l,r;
19         int ls,rs;
20     }a[maxn<<1];
21     int size;
22     SMT() {size=0;}
23     void build(int &x,int L,int R)
24     {
25         x=++size;
26         a[x].l=L;a[x].r=R;
27         a[x].Max=0;a[x].ans=0;
28         if (L==R) {a[x].ls=a[x].rs=0;return;}
29         const int mid=(L+R)>>1;
30         build(a[x].ls,L,mid);
31         build(a[x].rs,mid+1,R);
32     }
33     void build() {int x;build(x,1,n);}
34     int findans(int x,double v)
35     {
36 //        cout<<x<<endl;
37         if (a[x].Max-v<eps) return 0;
38         if (a[x].l==a[x].r) return 1;
39         const int &p=a[x].ls,&q=a[x].rs;
40         if (v-a[p].Max>-eps) return findans(q,v);
41         return findans(p,v)+a[x].ans-a[p].ans;
42     }
43     void up(int x)
44     {
45         const int &p=a[x].ls,&q=a[x].rs;
46         a[x].Max=max(a[p].Max,a[q].Max);
47         a[x].ans=a[p].ans+findans(q,a[p].Max);
48     }
49     int q;double v;
50     void besingle(int x,double v)
51     {
52         a[x].Max=v;
53         a[x].ans=1;
54     }
55     void be(int x)
56     {
57 //        cout<<x<<endl;
58         if (a[x].l==a[x].r && a[x].l==q) besingle(x,v);
59         else
60         {
61             const int mid=(a[x].l+a[x].r)>>1;
62             if (q<=mid) be(a[x].ls);
63             else be(a[x].rs);
64             up(x);
65         }
66     }
67     void be(int x,double v)
68     {
69         q=x;this->v=v;
70         be(1);
71     }
72 }t;
73 int main()
74 {
75     scanf("%d%d",&n,&m);
76     t.build();//cout<<":)";
77     int x,y;
78     for (int i=1;i<=m;i++)
79     {
80         scanf("%d%d",&x,&y);
81 //        assert(x<=n);
82         t.be(x,1.0*y/x);
83         printf("%d\n",t.a[1].ans);
84     }
85     return 0;
86 }
View Code

 

posted @ 2017-10-18 19:51  Blue233333  阅读(221)  评论(0编辑  收藏  举报