从前有条离散的山脉,这个离散的山脉由 n 个点组成,每个点的高度为 hi。根据大陆板块的那一套理论,这条山脉的形态会发生变化。具体的,每次大陆板块运动会导致一个区间的山脉高度变化。因为一些不可描述的原因,每次大陆板块运动,会使 l 到 r 中的所有点的高度加上一个等差数列{ai},并且{ai}的公差是正的。 一个点是山峰当且经当他比两侧的点都高。你需要求出每个时刻山峰的个数。
n, Q<=100000
【题解】
我们考虑差分序列。
根据bzoj1558的那一套理论,等差数列只要改变两个单点和一个区间,这里d>0,故是区间加。
差分后一个山峰对应的是a[i]>0,a[i+1]<0。这个拿线段树维护。
每次单点就暴力改。顺便维护区间负数最大值mx和非负数最小值mi。
如果mx+d<0且mi!=0,就说明这个区间加了这个对于答案没有影响,打tag。
如果mx+d>0,就说明这个区间答案要减小,递归下去。
如果mi==0,就说明这个区间答案可能要增大(看mi后跟的是什么了,如果跟的是负数,那么原来不算,mi变成正数就要算了)
暴力修改即可。
容易发现,区间内负数和0的个数最多为(n+2Q)个,所以复杂度是O(nlogn)
没考虑第二种情况(mi==0)WA了好久
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; const int mod = 1e9+7; const ll inf = 1e18; # define RG register # define ST static int n, m, Q, a[M], b[M]; struct SMT { int w[M]; ll mx[M], mi[M], le[M], ri[M], tag[M]; # define ls (x<<1) # define rs (x<<1|1) inline void pushtag(int x, ll d) { if(!x) return ; le[x] += d, ri[x] += d; if(mi[x] != inf) mi[x] += d; if(mx[x] != -inf) mx[x] += d; tag[x] += d; } inline void down(int x) { if(!x) return ; if(!tag[x]) return ; pushtag(ls, tag[x]); pushtag(rs, tag[x]); tag[x] = 0; } inline void up(int x) { if(!x) return ; w[x] = w[ls] + w[rs]; mx[x] = max(mx[ls], mx[rs]); mi[x] = min(mi[ls], mi[rs]); le[x] = le[ls]; ri[x] = ri[rs]; if(ri[ls] > 0 && le[rs] < 0) w[x] ++; } inline void build(int x, int l, int r) { tag[x] = 0; if(l == r) { le[x] = ri[x] = b[l]; if(b[l] < 0) mi[x] = inf, mx[x] = b[l]; else mi[x] = b[l], mx[x] = -inf; w[x] = 0; return ; } int mid = l+r>>1; build(ls, l, mid); build(rs, mid+1, r); up(x); } inline void go(int x, int l, int r, ll d) { if(l == r) { le[x] += d, ri[x] += d; if(le[x] < 0) mi[x] = inf, mx[x] = le[x]; else mi[x] = le[x], mx[x] = -inf; return ; } if(mx[x] + d < 0 && mi[x] != 0) { pushtag(x, d); return ; } down(x); int mid = l+r>>1; go(ls, l, mid, d); go(rs, mid+1, r, d); up(x); } inline void edt(int x, int l, int r, int L, int R, ll d) { if(L <= l && r <= R) { go(x, l, r, d); return ; } down(x); int mid = l+r>>1; if(L <= mid) edt(ls, l, mid, L, R, d); if(R > mid) edt(rs, mid+1, r, L, R, d); up(x); } inline void edt(int x, int l, int r, int pos, ll d) { if(l == r) { le[x] += d, ri[x] += d; if(le[x] < 0) mi[x] = inf, mx[x] = le[x]; else mi[x] = le[x], mx[x] = -inf; return ; } down(x); int mid = l+r>>1; if(pos <= mid) edt(ls, l, mid, pos, d); else edt(rs, mid+1, r, pos, d); up(x); } }T; int main() { freopen("ridge.in", "r", stdin); freopen("ridge.out", "w", stdout); cin >> n >> Q; for (int i=1; i<=n; ++i) scanf("%d", a+i); m = n-1; for (int i=1; i<=m; ++i) b[i] = a[i+1] - a[i]; T.build(1, 1, m); cout << T.w[1] << endl; int l, r, a1, d; while(Q--) { scanf("%d%d%d%d", &l, &r, &a1, &d); if(l != 1) { // l-1 add a1 T.edt(1, 1, m, l-1, (ll)a1); } // printf("%d ", T.w[1]); if(r != n) { // r add -(a1+(r-l)d) ll del = (ll)(l-r)*d-a1; T.edt(1, 1, m, r, del); } // printf("%d ", T.w[1]); if(l <= r-1) { // [l, r-1] add d T.edt(1, 1, m, l, r-1, d); } printf("%d ", T.w[1]); } return 0; }