[关闭]
@ysner 2018-04-24T19:32:06.000000Z 字数 1237 阅读 2125

Luogu4198 楼房重建

线段树


题面

带修改的区间维护最大斜率。
题面

解析

用线段树区间维护斜率。
考虑如何向上合并。
左半段一定有贡献。
如果左半段的最大斜率大于右半段,右半段无贡献。
否则,如果在右半段中,
左边大于左半段,则直接加上右边符合条件的(总左,因为右边现有的是大于左边的),递归考虑左边;
否则,递归右边。
这个玩意好像不能自然想出来。

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  11. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  12. using namespace std;
  13. const int N=1e5+100;
  14. int n,m,x,y;
  15. struct seg
  16. {
  17. double mk;int s;
  18. }t[N<<2];
  19. il int gi()
  20. {
  21. re int x=0,t=1;
  22. re char ch=getchar();
  23. while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  24. if(ch=='-') t=-1,ch=getchar();
  25. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  26. return x*t;
  27. }
  28. il int Query(re int now,re int l,re int r,re double k)
  29. {
  30. if(t[now].mk<=k) return 0;
  31. if(l==r) return 1;
  32. re int mid=l+r>>1;
  33. if(t[now<<1].mk>=k) return Query(now<<1,l,mid,k)+t[now].s-t[now<<1].s;
  34. else return Query(now<<1|1,mid+1,r,k);
  35. }
  36. il void Modify(re int now,re int l,re int r,re int x,re int z)
  37. {
  38. if(l==r)
  39. {
  40. t[now].mk=1.0*z/x;t[now].s=1;return;
  41. }
  42. re int mid=l+r>>1;
  43. if(x<=mid) Modify(now<<1,l,mid,x,z);
  44. else Modify(now<<1|1,mid+1,r,x,z);
  45. t[now].mk=max(t[now<<1].mk,t[now<<1|1].mk);
  46. t[now].s=t[now<<1].s+Query(now<<1|1,mid+1,r,t[now<<1].mk);
  47. }
  48. int main()
  49. {
  50. n=gi();m=gi();
  51. fp(i,1,m)
  52. {
  53. x=gi();y=gi();
  54. Modify(1,1,n,x,y);
  55. printf("%d\n",t[1].s);
  56. }
  57. return 0;
  58. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注