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

 

posted @ 2018-11-06 13:57  mrclr  阅读(163)  评论(0编辑  收藏  举报