• 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
  • 相关阅读:
    统计次数
    使用正则消除行号
    【收集】sql查询统计,周,月,年
    ASP.NET脚本过滤-防止跨站脚本攻击(收集别人的)
    win10环境下jdk1.8+Android Developer Tools Build: v22.3.0-887826的问题
    关于虚拟机的问题解决(转自豆瓣)
    工作
    numpy学习
    deepin Python pycharm安装
    pymysql连接和操作Mysql数据库
  • 原文地址:https://www.cnblogs.com/mrclr/p/9912983.html
Copyright © 2020-2023  润新知