线段树的一些用法
1.单调栈,存储前缀最大值
链接 洛谷:楼房重建
要求区间修改,线段树
关于如何 pushup 节点
父节点的 num = 左子节点的num + query(右子节点中大于左子节点的最大值的点的数目)
query中
如果当前区间的最大值已经小于等于所给标准 g ,返回0
如果l == r, 直接返回 a[l] > g
否则:
1.若当前节点的左子节点的 maxn 小于等于 g,则查询右区间
2. 否则,返回 query(左区间) + 该区间的 num - 左区间的 num(原因: 如果左区间的最大值已经大于 g,那么整个区间的最大值也一定大于 g,那么右区间中大于 g,且严格单增的节点数一定是 总区间的 num - 左区间的 num)
#include<bits/stdc++.h> const int MAXN = 1e5 + 10; using namespace std; struct node{ int l, r; double maxn; double minn; int num; }t[MAXN << 2]; int tot; int ro; int n, m; double a[MAXN]; int poi, x; int query(int rt, int l, int r, double g) { if(t[rt].maxn <= g) return 0; int mid = l + r >> 1; if(l == r) return a[l] > g; if(t[t[rt].l].maxn <= g) return query(t[rt].r, mid + 1, r, g); else return query(t[rt].l, l, mid, g) + t[rt].num - t[t[rt].l].num; } void update(int &rt, int l, int r, int poi, int x) { if(!rt) rt = ++tot; if(l == r) { if(l == poi) t[rt].maxn = t[rt].minn = (double)x / poi; t[rt].num = 1; return; } int mid = l + r >> 1; if(poi <= mid) update(t[rt].l, l, mid, poi, x); else update(t[rt].r, mid + 1, r, poi, x); t[rt].maxn = max(t[t[rt].l].maxn, t[t[rt].r].maxn); t[rt].num = t[t[rt].l].num + query(t[rt].r, mid + 1, r, t[t[rt].l].maxn); } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>> n >> m; for(int i = 1;i <= m;i++) { cin>> poi >> x; a[poi] = (double)x / poi; update(ro, 1, n, poi, x); cout << t[1].num << '\n'; } return 0; }

浙公网安备 33010602011771号