zoukankan      html  css  js  c++  java
  • luogu P4198 楼房重建

    嘟嘟嘟

     

    一道线段树好题啊。

    看到这道题后大概猜到是线段树,但是实在想不出来区间合并怎么写。最后还是学姐给我讲的。

    首先都知道要把高度转化成斜率,然后明确的一点就是如果该点斜率比上一次选的大,就一定要选,否则一定不选。也就是说每一个区间都是一个单调上升的子序列(但是和平常理解的LIS不同)。

     我们将斜率大小形象化为高度不一的线段,则两个区间的选取情况一定是这样的:

    左右子区间都是一个单调递增的序列。合并完后的答案应该是左区间的全部和右区间高出左区间的Max那一部分。那么可以想到在右区间里二分找第一个大于Max的答案。然而这样需要把每一个区间的答案都存下来,空间开不下。因此我们二分的时候模仿线段树查询,在右区间的子区间里递归查找。

    所以说区间合并是logn的,总复杂度O(nlog2n)。(神不神奇)

    斜率为了防止double掉精度,用向量存。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 3e5 + 5;
    21 inline ll read()
    22 {
    23   ll ans = 0;
    24   char ch = getchar(), last = ' ';
    25   while(!isdigit(ch)) last = ch, ch = getchar();
    26   while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    27   if(last == '-') ans = -ans;
    28   return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32   if(x < 0) x = -x, putchar('-');
    33   if(x >= 10) write(x / 10);
    34   putchar(x % 10 + '0');
    35 }
    36 
    37 int n, m;
    38 struct Vec
    39 {
    40   ll x, y;
    41   bool operator < (const Vec& oth)const
    42   {
    43     return y * oth.x < oth.y * x;
    44   }
    45 };
    46 struct Tree
    47 {
    48   int l, r, sum;
    49   Tree() {sum = 0;}
    50   Vec vec;
    51 }t[maxn << 2];
    52 
    53 void build(int L, int R, int now)
    54 {
    55   t[now].l = L; t[now].r = R;
    56   t[now].vec = (Vec){R, 0};
    57   if(L == R) return;
    58   int mid = (L + R) >> 1;
    59   build(L, mid, now << 1);
    60   build(mid + 1, R, now << 1 | 1);
    61 }
    62 int calc(Vec v, int now)
    63 {
    64   if(t[now].l == t[now].r) return v < t[now].vec;
    65   if(v < t[now << 1].vec) return calc(v, now << 1) + t[now].sum - t[now << 1].sum;
    66   else return calc(v, now << 1 | 1);
    67   
    68 }
    69 void update(int idx, int now, int d)
    70 {
    71   if(t[now].l == t[now].r)
    72     {
    73       t[now].vec = (Vec){idx, d};
    74       t[now].sum = d ? 1 : 0;  //d
    75       return;
    76     }
    77   int mid = (t[now].l + t[now].r) >> 1;
    78   if(idx <= mid) update(idx, now << 1, d);
    79   else update(idx, now << 1 | 1, d);
    80   t[now].vec = max(t[now << 1].vec, t[now << 1 | 1].vec);
    81   t[now].sum = t[now << 1].sum + calc(t[now << 1].vec, now << 1 | 1);
    82 }
    83 
    84 int main()
    85 {    
    86   n = read();  m = read();
    87   build(1, n, 1);
    88   for(int i = 1; i <= m; ++i)
    89     {
    90       int idx = read(), d = read();
    91       update(idx, 1, d);
    92       write(t[1].sum), enter;
    93     }
    94   return 0;
    95 }
    View Code
  • 相关阅读:
    通讯录封装实现
    简单通讯录的实现 main..h .m文件全部
    iOS 开发 OC编程 字典和集合 排序方法
    iOS 开发 OC编程 数组冒泡排序.图书管理
    iOS 开发 OC编程 属性和字符串练习
    iOS 开发 OC编程 属性和字符串
    iOS 开发 OC编程 便利构造器以及初始化方法
    iOS 开发 OC编程 方法的书写
    IOS 开发 OC编程 类和对象
    iOS 开发 c语言阶段考试题
  • 原文地址:https://www.cnblogs.com/mrclr/p/9912983.html
Copyright © 2011-2022 走看看