zoukankan      html  css  js  c++  java
  • 校内训练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
    ", 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;
    }
    View Code
  • 相关阅读:
    wordpress (net::ERR_TOO_MANY_REDIRECTS):重定向过多。
    Windows2003 IIS6完美实现WordPress伪静态的方法
    显示当前时间
    禁止搜索引擎收录的几种方法(全)
    MSClass 的使用(Class Of Marquee Scroll通用不间断滚动JS封装类)
    go to Top 返回顶部 例子
    电机位置和速度信号检测电路
    matlab polyfit 多项式拟合 (转自 百科)
    matlab contour
    DTC学习
  • 原文地址:https://www.cnblogs.com/galaxies/p/20170608_d.html
Copyright © 2011-2022 走看看