orz PoPoQQQ 的神题。
我的想法是:给每一个高度都维护一个 $01$ 序列,大概就是维护一个 $Map[i][j]$ 的矩阵,然后 $Map[i][j]$ 表示第 $i$ 根柱子的高度是否 $\ge j$。
那么怎么维护 $Map[i][j]$ 呢。。?
首先我们把柱子按照高度从小到大排序,然后依次给每个高度建主席树,初始时 $Map[i][0]$ 全是 $1$,然后如果当前高度 $i$ 比某个柱子 $j$ 的高度要大了,那么就单点修改 $Map[i][j]$,然后这个就是主席树动态开节点的经典操作嘛。然后我们就相当于是要维护每一个高度的主席树,并记录其最长连续子段,记高度 $i$ 的主席树的最长连续子段长 $len_i$,那么最大子矩阵就是:
$$max\{i\times len_i | i = 1 - Max\_height\}$$
然后每次单点修改只会改变一个主席树的最长连续子段,所以我们可以再弄一个堆维护这个答案。
时间空间复杂度均为 $O((n+m)\log h + h)$,可以过掉本题。
其实 $h$ 可以扩大到 $10^9$,这样的话我们就需要离散化一下,反正有用的高度只有 $O(n + m)$ 种。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <queue> 2 #include <cstdio> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 typedef long long LL; 7 #define N 100000 + 5 8 #define M 1000000 + 5 9 #define SIZE 10000000 + 5 10 11 int n, m, Max, tot, A[N], Ord[N], Root[M]; 12 13 struct Segment_Tree 14 { 15 int l, r, Lcombo, Rcombo, combo; 16 }h[SIZE]; 17 18 struct Node 19 { 20 int id; 21 LL square; 22 Node (int _id = 0, LL _square = 0) {id = _id, square = _square;} 23 bool operator < (const Node a) const 24 { 25 return square < a.square || (square == a.square && id < a.id); 26 } 27 }; 28 29 priority_queue <Node> Q; 30 31 inline LL getint() 32 { 33 char ch = '\n'; 34 for (; ch != '-' && (ch > '9' || ch < '0'); ch = getchar()) ; 35 int f = ch == '-' ? -1 : 1; 36 LL res = ch == '-' ? 0 : ch - '0'; 37 for (ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar()) 38 res = (res << 3) + (res << 1) + ch - '0'; 39 return res * f; 40 } 41 42 inline bool cmp(int u, int v) 43 { 44 return A[u] < A[v]; 45 } 46 47 inline void Build(int &x, int l, int r) 48 { 49 x = ++ tot; 50 h[x].Lcombo = h[x].Rcombo = h[x].combo = r - l + 1; 51 if (l == r) return ; 52 int mid = l + r >> 1; 53 Build(h[x].l, l, mid); 54 Build(h[x].r, mid + 1, r); 55 } 56 57 inline void update(int x, int l, int r) 58 { 59 int mid = l + r >> 1; 60 if (h[h[x].l].Lcombo == mid - l + 1) 61 h[x].Lcombo = h[h[x].l].Lcombo + h[h[x].r].Lcombo; 62 else h[x].Lcombo = h[h[x].l].Lcombo; 63 if (h[h[x].r].Rcombo == r - mid) 64 h[x].Rcombo = h[h[x].r].Rcombo + h[h[x].l].Rcombo; 65 else h[x].Rcombo = h[h[x].r].Rcombo; 66 h[x].combo = max(max(h[h[x].l].combo, h[h[x].r].combo), h[h[x].l].Rcombo + h[h[x].r].Lcombo); 67 } 68 69 inline void Modify(int &x, int l, int r, int t) 70 { 71 h[++ tot] = h[x]; 72 x = tot; 73 if (l == r) 74 { 75 h[x].Lcombo = h[x].Rcombo = h[x].combo = 0; 76 return ; 77 } 78 int mid = l + r >> 1; 79 if (t <= mid) Modify(h[x].l, l, mid, t); 80 else Modify(h[x].r, mid + 1, r, t); 81 update(x, l, r); 82 } 83 84 int main() 85 { 86 n = getint(), m = getint(); 87 for (int i = 1; i <= n; Ord[i] = i, i ++) 88 { 89 A[i] = getint(); 90 Max = max(Max, A[i]); 91 } 92 sort(Ord + 1, Ord + n + 1, cmp); 93 Build(Root[0], 1, n); 94 for (int i = 1, t = 1; i <= Max; i ++) 95 { 96 Root[i] = Root[i - 1]; 97 for (; A[Ord[t]] == i - 1 && t <= n; t ++) 98 Modify(Root[i], 1, n, Ord[t]); 99 Q.push(Node(i, (LL) h[Root[i]].combo * i)); 100 } 101 Node x = Q.top(); 102 LL last = x.square; 103 printf("%lld\n", last); 104 while (m --) 105 { 106 int pos = (int) (getint() ^ last); 107 Modify(Root[A[pos]], 1, n, pos); 108 Q.push(Node(A[pos], (LL) h[Root[A[pos]]].combo * A[pos])); 109 A[pos] --; 110 Node x; 111 for (x = Q.top(); (LL) x.id * h[Root[x.id]].combo != x.square; Q.pop(), x = Q.top()) ; 112 last = x.square; 113 printf("%lld\n", last); 114 } 115 116 return 0; 117 }