校内训练0608 山脉

从前有条离散的山脉,这个离散的山脉由 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\n", 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\n", T.w[1]);
        if(l <= r-1) {
            // [l, r-1] add d
            T.edt(1, 1, m, l, r-1, d); 
        }
        printf("%d\n", T.w[1]);
    }
    return 0;
}
View Code

 

posted @ 2017-06-08 15:12  Galaxies  阅读(150)  评论(0编辑  收藏  举报