樓房重建

不錯的一道題。c++

題意:每次修改一棟樓,求這些樓頂跟原點$(0,0)$的斜率單調上升長度(不是$\text{LIS}$)。git

由於一個樓房能被看到能夠等價於它的斜率比以前的任何一個都大。ui

這道題實際上知足區間合併,可是比較麻煩。spa

重點就在$\text{pushup}$的寫法。code

首先定義線段樹中區間的解即爲該對應區間內的單調上升長度。blog

兩個區間的合併:遞歸

如圖,發現右區間會受左區間的影響。get

左區間的答案爲$3$,右區間的答案爲$2$,但在合併後爲$3$。it

而這樣的話合併後爲$4$。class

因此右區間的答案主要受左區間最大值的影響。

令$cnt[o]$爲結點$o$的答案,因此維護中必定有$cnt[o]=cnt[lson]+get\_ans(cnt[rson])$。

如何$get\_ans$呢?

發現右區間受左區間最大值影響,因此必定受到$maxv[lson]$的約束。

觀察以下

若是$B$受到$A$的約束,那麼$C$、$D$也會受到$A$的約束。而後$D$也會受到$C$的約束。

若是$D$受到的約束中$A$沒有$C$強,即$maxv[A]<maxv[C]$,那麼只需遞歸處理$C$的區間再加上$D$貢獻的答案(這裏有個小細節,放後面談)。

由於區間$A,C$中最高的仍爲$maxv[C]$。

反之只需遞歸處理$D$區間,答案無需加上$C$(由於都被$A$擋住了)。

當遞歸到邊界了,也就只剩一個數了$maxv$,只要判斷是否大於約束便可(解爲$0//1$)

遞歸過程當中不須要修改$cnt$,由於區間內無需考慮區間外的影響(要想明白)。

根據以上能夠獲得下面的$\text{pushup}$:

1 int pushup(int o, int l, int r, double d) {
2     if (l == r) return maxv[o]-d > 1e-10 ? 1: 0;
3     int mid = (l + r) >> 1;
4     if (maxv[lson]-d > 1e-10) { // l > d
5         return pushup(lson, l, mid, d) + cnt[o] - cnt[lson];
6     } else { // l <= d
7         return pushup(rson, mid+1, r, d);
8     }
9 }

$d$表示約束,遞歸時須要下傳。

上面談到了一個問題:加上$D$貢獻的答案。

這裏是

return pushup(lson, l, mid, d) + cnt[o] - cnt[lson];

而不是

 return pushup(lson, l, mid, d) + cnt[rson];

要理解二者的差異:

後者是右區間不受左區間約束下的解;而前者是約束後的解$-$左區間的解(由於在一個區間內右區間必定受左區間約束),剩下的必定是約束後的右區間的解。

單點修改時,維護$maxv$時維護區間的$cnt$(這裏由於數值的修改包括在區間中,要對$cnt$進行修改)

也就是:

cnt[o] = cnt[lson] + pushup(rson, mid+1, r, maxv[lson]);

因而問題就解決了。

複雜度分析:單點修改$O(\log n)$,一次$\text{pushup}$須要$O(\log n)$,因此一次的複雜度爲$O(\log^2n)$。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define For(i, a, b, s) for (re int i = a; i <= b; s)
 9 #define maxx(a, b) a = max(a, b)
10 #define minn(a, b) a = min(a, b)
11 #define LL long long
12 #define INF (1 << 30)
13 
14 inline int read() {
15     int w = 0, f = 1; char c = getchar();
16     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
17     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
18     return w * f;
19 }
20 
21 const int maxn = 1e5 + 5, N = 100000;
22 
23 double a[maxn];
24 
25 struct SegT {
26 #define lson (o << 1)
27 #define rson (o << 1 | 1)
28     double maxv[maxn << 2];
29     int cnt[maxn << 2];
30     void build(int o, int l, int r) {
31         if (l == r) { cnt[o] = 1; return; }
32         int mid = (l + r) >> 1;
33         build(lson, l, mid); build(rson, mid+1, r);
34     }
35     void maintain(int o) { maxv[o] = max(maxv[lson], maxv[rson]); }
36     int pushup(int o, int l, int r, double d) {
37         if (l == r) return maxv[o]-d > 1e-10 ? 1: 0;
38         int mid = (l + r) >> 1;
39         if (maxv[lson]-d > 1e-10) { // l > o
40             return pushup(lson, l, mid, d) + cnt[o] - cnt[lson];
41         } else { // l <= o
42             return pushup(rson, mid+1, r, d);
43         }
44     }
45     void modify(int o, int l, int r, int x, int y) {
46         if (l == r) {
47             maxv[o] = (double)y / x;
48             cnt[o] = y ? 1 : 0;
49             return;
50         }
51         int mid = (l + r) >> 1;
52         if (x <= mid) modify(lson, l, mid, x, y); else modify(rson, mid+1, r, x, y);
53         maintain(o);
54         cnt[o] = cnt[lson] + pushup(rson, mid+1, r, maxv[lson]);
55     }
56 } T;
57 
58 int n, m;
59 int x, y;
60 
61 int main() {
62     n = read(); m = read();
63     rep(i, 1, m) {
64         x = read(), y = read();
65         T.modify(1, 1, N, x, y);
66         printf("%d\n", T.cnt[1]);
67     }
68     return 0;
69 }
相關文章
相關標籤/搜索