zoukankan      html  css  js  c++  java
  • 【数据结构】bzoj2957楼房重建

    Description

      小A的楼房外有一大片施工工地,工地上有N栋待建的楼房。每天,这片工地上的房子拆了又建、建了又拆。他经常无聊地看着窗外发呆,数自己能够看到多少栋房子。
      为了简化问题,我们考虑这些事件发生在一个二维平面上。小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度。如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。
      施工队的建造总共进行了M天。初始时,所有楼房都还没有开始建造,它们的高度均为0。在第i天,建筑队将会将横坐标为Xi的房屋的高度变为Yi(高度可以比原来大---修建,也可以比原来小---拆除,甚至可以保持不变---建筑队这天什么事也没做)。请你帮小A数数每天在建筑队完工之后,他能看到多少栋楼房?

    Input

      第一行两个正整数N,M
      接下来M行,每行两个正整数Xi,Yi

    Output


      M行,第i行一个整数表示第i天过后小A能看到的楼房有多少栋

    Sample Input


    3 4
    2 4
    3 6
    1 1000000000
    1 1

    Sample Output


    1
    1
    1
    2
    数据约定
      对于所有的数据1<=Xi<=N,1<=Yi<=10^9,N,M<=100000
     
     
     
    =========华丽丽的分割线============
    虽然是一个清华集训的题目,不过还是可做的嘛。。。
    一开始的时候自己写了一个程序,然后怎么都没有调出来。
    考虑本题,给出一个数列,然后要求支持单点修改以及询问比自己左边所有数都大的数就几个。
    考虑线段树,维护出一段中的高度最大值以及别的数都不考虑的情况下(这个一定不能漏)比这样的数有几个。
    考虑合并两个线段,高度的最大值是很容易合并的,直接取一个max就可以了。
    对于贡献度,我们发现一个线段的左半部分所有满足的数在原来的线段中一定满足,于是我们只需要考虑右半部分。
    我们写一个函数calc(node,k)表示node这个线段在左侧有一个大小为k的数的时候内部满足条件的数的个数。
    于是发现如果这个线段的左半部分的最大值小于等于k,那么左半部分贡献就是0,直接返回calc(node*2+1,k),
    如果左半部分最大值大于k,那么右半部分原本的个数是不会变的,然后再加上calc(node*2,k)就可以了,
    时间复杂度O(nlog^2n),
    听说这题卡精度,在吕爷爷的帮助下我学会了fraction,代码如下:
     1 #include <bits/stdc++.h>
     2 #define Maxn 100007
     3 using namespace std;
     4 int read()
     5 {
     6     int x=0,f=1;char ch=getchar();
     7     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     8     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     9     return x*f;
    10 }
    11 struct fraction
    12 {
    13     int dx,dy;
    14 };
    15 bool operator >(fraction a, fraction b)
    16 {
    17     return (1LL*a.dx*b.dy>1LL*a.dy*b.dx);
    18 }
    19 bool operator >=(fraction a, fraction b)
    20 {
    21     return (1LL*a.dx*b.dy>=1LL*a.dy*b.dx);
    22 }
    23 bool operator <(fraction a, fraction b)
    24 {
    25     return (1LL*a.dx*b.dy<1LL*a.dy*b.dx);
    26 }
    27 bool operator <=(fraction a, fraction b)
    28 {
    29     return (1LL*a.dx*b.dy<=1LL*a.dy*b.dx);
    30 }
    31 int n,m;
    32 struct seg
    33 {
    34     int lx,rx,cnt;
    35     fraction hmax;
    36 };
    37 seg tree[Maxn*4];
    38 void build(int node, int l, int r)
    39 {
    40     tree[node].lx=l,tree[node].rx=r,tree[node].cnt=0;
    41     tree[node].hmax=(fraction){0,1};
    42     if (tree[node].lx==tree[node].rx) return;
    43     int mid=(l+r)/2;
    44     build(node*2,l,mid),build(node*2+1,mid+1,r);
    45 }
    46 int calc(int node, fraction h)
    47 {
    48     if (tree[node].hmax<=h) return 0;
    49     if (tree[node].lx==tree[node].rx) return 1;
    50     if (tree[node*2].hmax<=h) return calc(node*2+1,h);
    51     else return tree[node].cnt-tree[node*2].cnt+calc(node*2,h);
    52 }
    53 void update(int node, int pos, fraction h)
    54 {
    55     if (tree[node].rx<pos) return;
    56     if (tree[node].lx>pos) return;
    57     if (tree[node].lx==tree[node].rx)
    58     {
    59         tree[node].hmax=h;
    60         tree[node].cnt=1;
    61         return;
    62     }
    63     update(node*2,pos,h),update(node*2+1,pos,h);
    64     tree[node].hmax=max(tree[node*2].hmax,tree[node*2+1].hmax);
    65     tree[node].cnt=tree[node*2].cnt+calc(node*2+1,tree[node*2].hmax);
    66 }
    67 int main()
    68 {
    69     n=read(),m=read();
    70     build(1,1,n);
    71     while (m--)
    72     {
    73         int x=read(),y=read();
    74         update(1,x,(fraction){y,x});
    75         printf("%d
    ",tree[1].cnt);
    76     }
    77     return 0;
    78 }
     
  • 相关阅读:
    HDU 2836 Traversal 简单DP + 树状数组
    UVa 1402 Runtime Error 伸展树
    UVa 11922
    HDU 4358 Boring counting 树状数组+思路
    HDU 4351 Digital root 线段树区间合并
    LA 6187
    UPC 2224 / “浪潮杯”山东省第四届ACM大学生程序设计竞赛 1008 Boring Counting 主席树
    max 宏定义取消:error C2589: error C2059: 语法错误 : “::”
    QT+VTK 对接使用
    标准C++中的string类的用法总结
  • 原文地址:https://www.cnblogs.com/Tommyr7/p/6946439.html
Copyright © 2011-2022 走看看