BZOJ 2957
1 /* 2 题意:BZOJ2957 n,m<=100000 在一个长度为n的直线上,每天在xi位置放置一个高度为yi的竖线,问每天在原点能够看到几个 3 题解:线段树解法,对于每个区间维护一个递增的序列,记录最大值,和最长的增长的长度 4 查询操作: 查询l,r区间大于M的有单调递增的有几个,如果左区间的最大值>=M,那么答案在右区间,否则,我们答案受到左区间的影响,可以用总长度-左区间的长度+左区间的询问长度 5 更新操作: 维护区间的最大值, 6 区间的最长的长度的更新: 左区间的长度+ 右区间大于左区间最大值的长度 7 时间:2018.07.19 8 */ 9 10 #include <bits/stdc++.h> 11 using namespace std; 12 13 typedef long long LL; 14 const int MAXN = 100005; 15 const LL MOD7 = 1e9+7; 16 17 18 struct TreeNode 19 { 20 int l,r; 21 int ans; 22 double maxv; 23 }f[4*MAXN]; 24 25 void build(int t,int l,int r) 26 { 27 f[t].l=l;f[t].r=r; 28 f[t].ans=0;f[t].maxv=0; 29 if (l==r) return; 30 int mid=(l+r)/2; 31 build(2*t,l,mid); 32 build(2*t+1,mid+1,r); 33 } 34 35 int query(int t,int l,int r,double M) 36 { 37 // printf("query %d %d %d %lf\n",t, l, r, M); 38 if (l==r) return f[t].maxv>M; 39 int mid=(f[t].l+f[t].r)/2; 40 if (f[2*t].maxv<=M) return query(2*t+1,mid+1,r,M); 41 return f[t].ans-f[2*t].ans+query(2*t,l,mid,M); 42 } 43 44 void update(int t,int k,double M) 45 { 46 if (f[t].l==k && f[t].r==k) 47 { 48 f[t].ans=1; 49 f[t].maxv=M; 50 return; 51 } 52 int mid=(f[t].l+f[t].r)/2; 53 if (k<=mid) update(2*t,k,M); 54 else update(2*t+1,k,M); 55 f[t].maxv = max(f[2*t].maxv,f[2*t+1].maxv); 56 f[t].ans=f[2*t].ans+query(2*t+1,mid+1,f[t].r,f[2*t].maxv); 57 } 58 59 int n,m; 60 61 int main() 62 { 63 #ifndef ONLINE_JUDGE 64 freopen("test.txt","r",stdin); 65 #endif // ONLINE_JUDGE 66 scanf("%d%d",&n,&m); 67 build(1, 1, n); 68 int x,y; 69 for (int i=1;i<=m;++i) 70 { 71 scanf("%d%d",&x,&y); 72 update(1,x,1.0*y/x); 73 // printf("%d\n",query(1,0,n,0)); 74 printf("%d\n",f[1].ans); 75 } 76 return 0; 77 }