P4198 楼房重建

题面

• 线段树维护的题,关键在于合并区间答案。

• ans 数组记录每一段区间的答案。

• 然后会发现对于每一个子序列,有两种点在当前子序列中一定满足要求:

 1. 子序列中的第一个点。

 2. 子序列中权值最大的点。

• 而且 pushup 时,左儿子的 ans 值会被父节点全部接受。

• 通过上面两个性质便能得出 pushup 的做法。

 1 #include<bits/stdc++.h>
 2 #define ls u<<1
 3 #define rs ls|1
 4 using namespace std;
 5 int n,m;
 6 int x,y;
 7 double tmp;
 8 int ans[400050];
 9 double val[100050];
10 double maxn[400050];
11 int query(int u,int l,int r,double hig)
12 {
13     if(val[l]>hig)    return ans[u];
14     if(maxn[u]<=hig)    return 0;
15     int mid=(l+r)>>1;
16     if(maxn[ls]<=hig)    return query(rs,mid+1,r,hig);
17     else    return query(ls,l,mid,hig)+ans[u]-ans[ls];
18 }
19 void modify(int u,int l,int r)
20 {
21     if(l==r)
22     {
23         maxn[u]=val[x];
24         ans[u]=1;
25         return ;
26     }
27     int mid=(l+r)>>1;
28     if(x<=mid)    modify(ls,l,mid);
29     else    modify(rs,mid+1,r);
30     maxn[u]=max(maxn[ls],maxn[rs]);
31     ans[u]=ans[ls]+query(rs,mid+1,r,maxn[ls]);
32 }
33 int main()
34 {
35     scanf("%d%d",&n,&m);
36     while(m--)
37     {
38         scanf("%d%d",&x,&y);
39         val[x]=(double)y/x;
40         modify(1,1,n);
41         printf("%d\n",ans[1]);
42     }
43     return 0;
44 }
View Code

 

  

posted @ 2019-02-25 23:21  Hevix  阅读(125)  评论(0编辑  收藏  举报